Merge pull request #649 from metamaps/feature/Metamaps-in-frontend
move Metamaps code to webpack
This commit is contained in:
commit
eef8a281cb
61 changed files with 4147 additions and 6820 deletions
|
@ -18,4 +18,4 @@ before_script:
|
|||
- nvm use stable
|
||||
- npm install
|
||||
script:
|
||||
- bundle exec rspec && npm test && bundle exec brakeman -q -z
|
||||
- bundle exec rspec && bundle exec brakeman -q -z && npm test
|
||||
|
|
|
@ -332,8 +332,5 @@ DEPENDENCIES
|
|||
uglifier
|
||||
uservoice-ruby
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.3.0p0
|
||||
|
||||
BUNDLED WITH
|
||||
1.12.5
|
||||
|
|
|
@ -13,37 +13,7 @@
|
|||
//= require jquery
|
||||
//= require jquery-ui
|
||||
//= require jquery_ujs
|
||||
//= require ./webpacked/metamaps.bundle
|
||||
//= require_directory ./lib
|
||||
//= require ./src/Metamaps.GlobalUI
|
||||
//= require ./src/Metamaps.Router
|
||||
//= require ./src/Metamaps.Backbone
|
||||
//= require ./src/Metamaps.Views
|
||||
//= require ./src/views/chatView
|
||||
//= require ./src/views/videoView
|
||||
//= require ./src/views/room
|
||||
//= require ./src/JIT
|
||||
//= require ./src/Metamaps.Erb
|
||||
//= require ./webpacked/metamaps.bundle
|
||||
//= require ./src/check-canvas-support
|
||||
//= require ./src/Metamaps
|
||||
//= require ./src/Metamaps.Create
|
||||
//= require ./src/Metamaps.TopicCard
|
||||
//= require ./src/Metamaps.SynapseCard
|
||||
//= require ./src/Metamaps.Visualize
|
||||
//= require ./src/Metamaps.Util
|
||||
//= require ./src/Metamaps.Realtime
|
||||
//= require ./src/Metamaps.Control
|
||||
//= require ./src/Metamaps.Filter
|
||||
//= require ./src/Metamaps.Listeners
|
||||
//= require ./src/Metamaps.Organize
|
||||
//= require ./src/Metamaps.Topic
|
||||
//= require ./src/Metamaps.Synapse
|
||||
//= require ./src/Metamaps.Map
|
||||
//= require ./src/Metamaps.Account
|
||||
//= require ./src/Metamaps.Mapper
|
||||
//= require ./src/Metamaps.Mobile
|
||||
//= require ./src/Metamaps.Admin
|
||||
//= require ./src/Metamaps.Import
|
||||
//= require ./src/Metamaps.AutoLayout
|
||||
//= require ./src/Metamaps.PasteInput
|
||||
//= require ./src/Metamaps.JIT
|
||||
//= require ./src/Metamaps.Debug
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Metamaps.Debug.js.erb
|
||||
*
|
||||
* Dependencies: none!
|
||||
*/
|
||||
|
||||
Metamaps.Debug = function () {
|
||||
console.debug(Metamaps)
|
||||
console.debug('Metamaps Version: ' + Metamaps.VERSION)
|
||||
}
|
||||
Metamaps.debug = function () {
|
||||
Metamaps.Debug()
|
||||
}
|
20
app/assets/javascripts/src/Metamaps.Erb.js.erb
Normal file
20
app/assets/javascripts/src/Metamaps.Erb.js.erb
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* global Metamaps */
|
||||
|
||||
/*
|
||||
* Metamaps.Erb.js.erb
|
||||
*/
|
||||
|
||||
/* erb variables from rails */
|
||||
window.Metamaps = window.Metamaps || {}
|
||||
Metamaps.Erb = {}
|
||||
Metamaps.Erb['REALTIME_SERVER'] = '<%= ENV['REALTIME_SERVER'] %>'
|
||||
Metamaps.Erb['junto_spinner_darkgrey.gif'] = '<%= asset_path('junto_spinner_darkgrey.gif') %>'
|
||||
Metamaps.Erb['user.png'] = '<%= asset_path('user.png') %>'
|
||||
Metamaps.Erb['icons/wildcard.png'] = '<%= asset_path('icons/wildcard.png') %>'
|
||||
Metamaps.Erb['topic_description_signifier.png'] = '<%= asset_path('topic_description_signifier.png') %>'
|
||||
Metamaps.Erb['topic_link_signifier.png'] = '<%= asset_path('topic_link_signifier.png') %>'
|
||||
Metamaps.Erb['synapse16.png'] = '<%= asset_path('synapse16.png') %>'
|
||||
Metamaps.Erb['sounds/MM_sounds.mp3'] = '<%= asset_path 'sounds/MM_sounds.mp3' %>'
|
||||
Metamaps.Erb['sounds/MM_sounds.ogg'] = '<%= asset_path 'sounds/MM_sounds.ogg' %>'
|
||||
Metamaps.Metacodes = <%= Metacode.all.to_json.gsub(%r[(icon.*?)(\"},)], '\1?purple=stupid\2').html_safe %>
|
||||
Metamaps.VERSION = '<%= METAMAPS_VERSION %>'
|
|
@ -1,717 +0,0 @@
|
|||
var Metamaps = window.Metamaps || {}; // this variable declaration defines a Javascript object that will contain all the variables and functions used by us, broken down into 'sub-modules' that look something like this
|
||||
/*
|
||||
|
||||
* unless you are on a page with the Javascript InfoVis Toolkit (Topic or Map) the only section in the metamaps
|
||||
* object will be these
|
||||
GlobalUI
|
||||
Active
|
||||
Maps
|
||||
Mappers
|
||||
Backbone
|
||||
|
||||
* all these get added when you are on a page with the Javascript Infovis Toolkit
|
||||
Settings
|
||||
Touch
|
||||
Mouse
|
||||
Selected
|
||||
Metacodes
|
||||
Topics
|
||||
Synapses
|
||||
Mappings
|
||||
Create
|
||||
TopicCard
|
||||
SynapseCard
|
||||
Visualize
|
||||
Util
|
||||
Realtime
|
||||
Control
|
||||
Filter
|
||||
Listeners
|
||||
Organize
|
||||
Map
|
||||
Mapper
|
||||
Topic
|
||||
Synapse
|
||||
JIT
|
||||
*/
|
||||
|
||||
Metamaps.Active = {
|
||||
Map: null,
|
||||
Topic: null,
|
||||
Mapper: null
|
||||
};
|
||||
Metamaps.Maps = {};
|
||||
|
||||
$(document).ready(function () {
|
||||
// initialize all the modules
|
||||
for (var prop in Metamaps) {
|
||||
// this runs the init function within each sub-object on the Metamaps one
|
||||
if (Metamaps.hasOwnProperty(prop) &&
|
||||
Metamaps[prop] != null &&
|
||||
Metamaps[prop].hasOwnProperty('init') &&
|
||||
typeof (Metamaps[prop].init) == 'function'
|
||||
) {
|
||||
Metamaps[prop].init()
|
||||
}
|
||||
}
|
||||
// load whichever page you are on
|
||||
if (Metamaps.currentSection === "explore") {
|
||||
var capitalize = Metamaps.currentPage.charAt(0).toUpperCase() + Metamaps.currentPage.slice(1)
|
||||
|
||||
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] )
|
||||
if (Metamaps.currentPage === "mapper") {
|
||||
Metamaps.Views.exploreMaps.fetchUserThenRender()
|
||||
}
|
||||
else {
|
||||
Metamaps.Views.exploreMaps.render()
|
||||
}
|
||||
Metamaps.GlobalUI.showDiv('#explore')
|
||||
}
|
||||
else if (Metamaps.currentSection === "" && Metamaps.Active.Mapper) {
|
||||
Metamaps.Views.exploreMaps.setCollection(Metamaps.Maps.Active)
|
||||
Metamaps.Views.exploreMaps.render()
|
||||
Metamaps.GlobalUI.showDiv('#explore')
|
||||
}
|
||||
else if (Metamaps.Active.Map || Metamaps.Active.Topic) {
|
||||
Metamaps.Loading.show()
|
||||
Metamaps.JIT.prepareVizData()
|
||||
Metamaps.GlobalUI.showDiv('#infovis')
|
||||
}
|
||||
});
|
||||
|
||||
Metamaps.GlobalUI = {
|
||||
notifyTimeout: null,
|
||||
lightbox: null,
|
||||
init: function () {
|
||||
var self = Metamaps.GlobalUI;
|
||||
|
||||
self.Search.init();
|
||||
self.CreateMap.init();
|
||||
self.Account.init();
|
||||
|
||||
if ($('#toast').html().trim()) self.notifyUser($('#toast').html())
|
||||
|
||||
//bind lightbox clicks
|
||||
$('.openLightbox').click(function (event) {
|
||||
self.openLightbox($(this).attr('data-open'));
|
||||
event.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#lightbox_screen, #lightbox_close').click(self.closeLightbox);
|
||||
|
||||
// initialize global backbone models and collections
|
||||
if (Metamaps.Active.Mapper) Metamaps.Active.Mapper = new Metamaps.Backbone.Mapper(Metamaps.Active.Mapper);
|
||||
|
||||
var myCollection = Metamaps.Maps.Mine ? Metamaps.Maps.Mine : [];
|
||||
var sharedCollection = Metamaps.Maps.Shared ? Metamaps.Maps.Shared : [];
|
||||
var starredCollection = Metamaps.Maps.Starred ? Metamaps.Maps.Starred : [];
|
||||
var mapperCollection = [];
|
||||
var mapperOptionsObj = {id: 'mapper', sortBy: 'updated_at' };
|
||||
if (Metamaps.Maps.Mapper) {
|
||||
mapperCollection = Metamaps.Maps.Mapper.models;
|
||||
mapperOptionsObj.mapperId = Metamaps.Maps.Mapper.id;
|
||||
}
|
||||
var featuredCollection = Metamaps.Maps.Featured ? Metamaps.Maps.Featured : [];
|
||||
var activeCollection = Metamaps.Maps.Active ? Metamaps.Maps.Active : [];
|
||||
Metamaps.Maps.Mine = new Metamaps.Backbone.MapsCollection(myCollection, {id: 'mine', sortBy: 'updated_at' });
|
||||
Metamaps.Maps.Shared = new Metamaps.Backbone.MapsCollection(sharedCollection, {id: 'shared', sortBy: 'updated_at' });
|
||||
Metamaps.Maps.Starred = new Metamaps.Backbone.MapsCollection(starredCollection, {id: 'starred', sortBy: 'updated_at' });
|
||||
// 'Mapper' refers to another mapper
|
||||
Metamaps.Maps.Mapper = new Metamaps.Backbone.MapsCollection(mapperCollection, mapperOptionsObj);
|
||||
Metamaps.Maps.Featured = new Metamaps.Backbone.MapsCollection(featuredCollection, {id: 'featured', sortBy: 'updated_at' });
|
||||
Metamaps.Maps.Active = new Metamaps.Backbone.MapsCollection(activeCollection, {id: 'active', sortBy: 'updated_at' });
|
||||
},
|
||||
showDiv: function (selector) {
|
||||
$(selector).show()
|
||||
$(selector).animate({
|
||||
opacity: 1
|
||||
}, 200, 'easeOutCubic')
|
||||
},
|
||||
hideDiv: function (selector) {
|
||||
$(selector).animate({
|
||||
opacity: 0
|
||||
}, 200, 'easeInCubic', function () { $(this).hide() })
|
||||
},
|
||||
openLightbox: function (which) {
|
||||
var self = Metamaps.GlobalUI;
|
||||
|
||||
$('.lightboxContent').hide();
|
||||
$('#' + which).show();
|
||||
|
||||
self.lightbox = which;
|
||||
|
||||
$('#lightbox_overlay').show();
|
||||
|
||||
var heightOfContent = '-' + ($('#lightbox_main').height() / 2) + 'px';
|
||||
// animate the content in from the bottom
|
||||
$('#lightbox_main').animate({
|
||||
'top': '50%',
|
||||
'margin-top': heightOfContent
|
||||
}, 200, 'easeOutCubic');
|
||||
|
||||
// fade the black overlay in
|
||||
$('#lightbox_screen').animate({
|
||||
'opacity': '0.42'
|
||||
}, 200);
|
||||
|
||||
if (which == "switchMetacodes") {
|
||||
Metamaps.Create.isSwitchingSet = true;
|
||||
}
|
||||
},
|
||||
|
||||
closeLightbox: function (event) {
|
||||
var self = Metamaps.GlobalUI;
|
||||
|
||||
if (event) event.preventDefault();
|
||||
|
||||
// animate the lightbox content offscreen
|
||||
$('#lightbox_main').animate({
|
||||
'top': '100%',
|
||||
'margin-top': '0'
|
||||
}, 200, 'easeInCubic');
|
||||
|
||||
// fade the black overlay out
|
||||
$('#lightbox_screen').animate({
|
||||
'opacity': '0.0'
|
||||
}, 200, function () {
|
||||
$('#lightbox_overlay').hide();
|
||||
});
|
||||
|
||||
if (self.lightbox === 'forkmap') Metamaps.GlobalUI.CreateMap.reset('fork_map');
|
||||
if (self.lightbox === 'newmap') Metamaps.GlobalUI.CreateMap.reset('new_map');
|
||||
if (Metamaps.Create && Metamaps.Create.isSwitchingSet) {
|
||||
Metamaps.Create.cancelMetacodeSetSwitch();
|
||||
}
|
||||
self.lightbox = null;
|
||||
},
|
||||
notifyUser: function (message, leaveOpen) {
|
||||
var self = Metamaps.GlobalUI;
|
||||
|
||||
$('#toast').html(message)
|
||||
self.showDiv('#toast')
|
||||
clearTimeout(self.notifyTimeOut);
|
||||
if (!leaveOpen) {
|
||||
self.notifyTimeOut = setTimeout(function () {
|
||||
self.hideDiv('#toast')
|
||||
}, 8000);
|
||||
}
|
||||
},
|
||||
clearNotify: function() {
|
||||
var self = Metamaps.GlobalUI;
|
||||
|
||||
clearTimeout(self.notifyTimeOut);
|
||||
self.hideDiv('#toast')
|
||||
},
|
||||
shareInvite: function(inviteLink) {
|
||||
window.prompt("To copy the invite link, press: Ctrl+C, Enter", inviteLink);
|
||||
}
|
||||
};
|
||||
|
||||
Metamaps.GlobalUI.CreateMap = {
|
||||
newMap: null,
|
||||
emptyMapForm: "",
|
||||
emptyForkMapForm: "",
|
||||
topicsToMap: [],
|
||||
synapsesToMap: [],
|
||||
init: function () {
|
||||
var self = Metamaps.GlobalUI.CreateMap;
|
||||
|
||||
self.newMap = new Metamaps.Backbone.Map({ permission: 'commons' });
|
||||
|
||||
self.bindFormEvents();
|
||||
|
||||
self.emptyMapForm = $('#new_map').html();
|
||||
|
||||
},
|
||||
bindFormEvents: function () {
|
||||
var self = Metamaps.GlobalUI.CreateMap;
|
||||
|
||||
$('.new_map input, .new_map div').unbind('keypress').bind('keypress', function(event) {
|
||||
if (event.keyCode === 13) self.submit()
|
||||
})
|
||||
|
||||
$('.new_map button.cancel').unbind().bind('click', function (event) {
|
||||
event.preventDefault();
|
||||
Metamaps.GlobalUI.closeLightbox();
|
||||
});
|
||||
$('.new_map button.submitMap').unbind().bind('click', self.submit);
|
||||
|
||||
// bind permission changer events on the createMap form
|
||||
$('.permIcon').unbind().bind('click', self.switchPermission);
|
||||
},
|
||||
closeSuccess: function () {
|
||||
$('#mapCreatedSuccess').fadeOut(300, function(){
|
||||
$(this).remove();
|
||||
});
|
||||
},
|
||||
generateSuccessMessage: function (id) {
|
||||
var stringStart = "<div id='mapCreatedSuccess'><h6>SUCCESS!</h6>Your map has been created. Do you want to: <a id='mapGo' href='/maps/";
|
||||
stringStart += id;
|
||||
stringStart += "' onclick='Metamaps.GlobalUI.CreateMap.closeSuccess();'>Go to your new map</a>";
|
||||
stringStart += "<span>OR</span><a id='mapStay' href='#' onclick='Metamaps.GlobalUI.CreateMap.closeSuccess(); return false;'>Stay on this ";
|
||||
var page = Metamaps.Active.Map ? 'map' : 'page';
|
||||
var stringEnd = "</a></div>";
|
||||
return stringStart + page + stringEnd;
|
||||
},
|
||||
switchPermission: function () {
|
||||
var self = Metamaps.GlobalUI.CreateMap;
|
||||
|
||||
self.newMap.set('permission', $(this).attr('data-permission'));
|
||||
$(this).siblings('.permIcon').find('.mapPermIcon').removeClass('selected');
|
||||
$(this).find('.mapPermIcon').addClass('selected');
|
||||
|
||||
var permText = $(this).find('.tip').html();
|
||||
$(this).parents('.new_map').find('.permText').html(permText);
|
||||
},
|
||||
submit: function (event) {
|
||||
if (event) event.preventDefault();
|
||||
|
||||
var self = Metamaps.GlobalUI.CreateMap;
|
||||
|
||||
if (Metamaps.GlobalUI.lightbox === 'forkmap') {
|
||||
self.newMap.set('topicsToMap', self.topicsToMap);
|
||||
self.newMap.set('synapsesToMap', self.synapsesToMap);
|
||||
}
|
||||
|
||||
var formId = Metamaps.GlobalUI.lightbox === 'forkmap' ? '#fork_map' : '#new_map';
|
||||
var $form = $(formId);
|
||||
|
||||
self.newMap.set('name', $form.find('#map_name').val());
|
||||
self.newMap.set('desc', $form.find('#map_desc').val());
|
||||
|
||||
if (self.newMap.get('name').length===0){
|
||||
self.throwMapNameError();
|
||||
return;
|
||||
}
|
||||
|
||||
self.newMap.save(null, {
|
||||
success: self.success
|
||||
// TODO add error message
|
||||
});
|
||||
|
||||
Metamaps.GlobalUI.closeLightbox();
|
||||
Metamaps.GlobalUI.notifyUser('Working...');
|
||||
},
|
||||
throwMapNameError: function () {
|
||||
var self = Metamaps.GlobalUI.CreateMap;
|
||||
|
||||
var formId = Metamaps.GlobalUI.lightbox === 'forkmap' ? '#fork_map' : '#new_map';
|
||||
var $form = $(formId);
|
||||
|
||||
var message = $("<div class='feedback_message'>Please enter a map name...</div>");
|
||||
|
||||
$form.find('#map_name').after(message);
|
||||
setTimeout(function(){
|
||||
message.fadeOut('fast', function(){
|
||||
message.remove();
|
||||
});
|
||||
}, 5000);
|
||||
},
|
||||
success: function (model) {
|
||||
var self = Metamaps.GlobalUI.CreateMap;
|
||||
|
||||
//push the new map onto the collection of 'my maps'
|
||||
Metamaps.Maps.Mine.add(model);
|
||||
|
||||
var formId = Metamaps.GlobalUI.lightbox === 'forkmap' ? '#fork_map' : '#new_map';
|
||||
var form = $(formId);
|
||||
|
||||
Metamaps.GlobalUI.clearNotify();
|
||||
$('#wrapper').append(self.generateSuccessMessage(model.id));
|
||||
|
||||
},
|
||||
reset: function (id) {
|
||||
var self = Metamaps.GlobalUI.CreateMap;
|
||||
|
||||
var form = $('#' + id);
|
||||
|
||||
if (id === "fork_map") {
|
||||
self.topicsToMap = [];
|
||||
self.synapsesToMap = [];
|
||||
form.html(self.emptyForkMapForm);
|
||||
}
|
||||
else {
|
||||
form.html(self.emptyMapForm);
|
||||
}
|
||||
|
||||
self.bindFormEvents();
|
||||
self.newMap = new Metamaps.Backbone.Map({ permission: 'commons' });
|
||||
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Metamaps.GlobalUI.Account = {
|
||||
isOpen: false,
|
||||
changing: false,
|
||||
init: function () {
|
||||
var self = Metamaps.GlobalUI.Account;
|
||||
|
||||
$('.sidebarAccountIcon').click(self.toggleBox);
|
||||
$('.sidebarAccountBox').click(function(event){
|
||||
event.stopPropagation();
|
||||
});
|
||||
$('body').click(self.close);
|
||||
},
|
||||
toggleBox: function (event) {
|
||||
var self = Metamaps.GlobalUI.Account;
|
||||
|
||||
if (self.isOpen) self.close();
|
||||
else self.open();
|
||||
|
||||
event.stopPropagation();
|
||||
},
|
||||
open: function () {
|
||||
var self = Metamaps.GlobalUI.Account;
|
||||
|
||||
Metamaps.Filter.close();
|
||||
$('.sidebarAccountIcon .tooltipsUnder').addClass('hide');
|
||||
|
||||
|
||||
if (!self.isOpen && !self.changing) {
|
||||
self.changing = true;
|
||||
$('.sidebarAccountBox').fadeIn(200, function () {
|
||||
self.changing = false;
|
||||
self.isOpen = true;
|
||||
$('.sidebarAccountBox #user_email').focus();
|
||||
});
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
var self = Metamaps.GlobalUI.Account;
|
||||
|
||||
$('.sidebarAccountIcon .tooltipsUnder').removeClass('hide');
|
||||
if (!self.changing) {
|
||||
self.changing = true;
|
||||
$('.sidebarAccountBox #user_email').blur();
|
||||
$('.sidebarAccountBox').fadeOut(200, function () {
|
||||
self.changing = false;
|
||||
self.isOpen = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
Metamaps.GlobalUI.Search = {
|
||||
locked: false,
|
||||
isOpen: false,
|
||||
limitTopicsToMe: false,
|
||||
limitMapsToMe: false,
|
||||
timeOut: null,
|
||||
changing: false,
|
||||
optionsInitialized: false,
|
||||
init: function () {
|
||||
var self = Metamaps.GlobalUI.Search;
|
||||
|
||||
var loader = new CanvasLoader('searchLoading');
|
||||
loader.setColor('#4fb5c0'); // default is '#000000'
|
||||
loader.setDiameter(24); // default is 40
|
||||
loader.setDensity(41); // default is 40
|
||||
loader.setRange(0.9); // default is 1.3
|
||||
loader.show(); // Hidden by default
|
||||
|
||||
// bind the hover events
|
||||
$(".sidebarSearch").hover(function () {
|
||||
self.open()
|
||||
}, function () {
|
||||
self.close(800, false)
|
||||
});
|
||||
|
||||
$('.sidebarSearchIcon').click(function (e) {
|
||||
$('.sidebarSearchField').focus();
|
||||
});
|
||||
$('.sidebarSearch').click(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
$('body').click(function (e) {
|
||||
self.close(0, false);
|
||||
});
|
||||
|
||||
// open if the search is closed and user hits ctrl+/
|
||||
// close if they hit ESC
|
||||
$('body').bind('keyup', function (e) {
|
||||
switch (e.which) {
|
||||
case 191:
|
||||
if ((e.ctrlKey && !self.isOpen) || (e.ctrlKey && self.locked)) {
|
||||
self.open(true); // true for focus
|
||||
}
|
||||
break;
|
||||
case 27:
|
||||
if (self.isOpen) {
|
||||
self.close(0, true);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break; //console.log(e.which);
|
||||
}
|
||||
});
|
||||
|
||||
self.startTypeahead();
|
||||
},
|
||||
lock: function() {
|
||||
var self = Metamaps.GlobalUI.Search;
|
||||
self.locked = true;
|
||||
},
|
||||
unlock: function() {
|
||||
var self = Metamaps.GlobalUI.Search;
|
||||
self.locked = false;
|
||||
},
|
||||
open: function (focus) {
|
||||
var self = Metamaps.GlobalUI.Search;
|
||||
|
||||
clearTimeout(self.timeOut);
|
||||
if (!self.isOpen && !self.changing && !self.locked) {
|
||||
self.changing = true;
|
||||
$('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({
|
||||
width: '400px'
|
||||
}, 300, function () {
|
||||
if (focus) $('.sidebarSearchField').focus();
|
||||
$('.sidebarSearchField, .sidebarSearch .tt-hint').css({
|
||||
padding: '7px 10px 3px 10px',
|
||||
width: '380px'
|
||||
});
|
||||
self.changing = false;
|
||||
self.isOpen = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
close: function (closeAfter, bypass) {
|
||||
// for now
|
||||
return
|
||||
|
||||
var self = Metamaps.GlobalUI.Search;
|
||||
|
||||
self.timeOut = setTimeout(function () {
|
||||
if (!self.locked && !self.changing && self.isOpen && (bypass || $('.sidebarSearchField.tt-input').val() == '')) {
|
||||
self.changing = true;
|
||||
$('.sidebarSearchField, .sidebarSearch .tt-hint').css({
|
||||
padding: '7px 0 3px 0',
|
||||
width: '400px'
|
||||
});
|
||||
$('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({
|
||||
width: '0'
|
||||
}, 300, function () {
|
||||
$('.sidebarSearchField').typeahead('val', '');
|
||||
$('.sidebarSearchField').blur();
|
||||
self.changing = false;
|
||||
self.isOpen = false;
|
||||
});
|
||||
}
|
||||
}, closeAfter);
|
||||
},
|
||||
startTypeahead: function () {
|
||||
var self = Metamaps.GlobalUI.Search;
|
||||
|
||||
var mapheader = Metamaps.Active.Mapper ? '<div class="searchMapsHeader searchHeader"><h3 class="search-heading">Maps</h3><input type="checkbox" class="limitToMe" id="limitMapsToMe"></input><label for="limitMapsToMe" class="limitToMeLabel">added by me</label><div class="minimizeResults minimizeMapResults"></div><div class="clearfloat"></div></div>' : '<div class="searchMapsHeader searchHeader"><h3 class="search-heading">Maps</h3><div class="minimizeResults minimizeMapResults"></div><div class="clearfloat"></div></div>';
|
||||
var topicheader = Metamaps.Active.Mapper ? '<div class="searchTopicsHeader searchHeader"><h3 class="search-heading">Topics</h3><input type="checkbox" class="limitToMe" id="limitTopicsToMe"></input><label for="limitTopicsToMe" class="limitToMeLabel">added by me</label><div class="minimizeResults minimizeTopicResults"></div><div class="clearfloat"></div></div>' : '<div class="searchTopicsHeader searchHeader"><h3 class="search-heading">Topics</h3><div class="minimizeResults minimizeTopicResults"></div><div class="clearfloat"></div></div>';
|
||||
var mapperheader = '<div class="searchMappersHeader searchHeader"><h3 class="search-heading">Mappers</h3><div class="minimizeResults minimizeMapperResults"></div><div class="clearfloat"></div></div>';
|
||||
|
||||
var topics = {
|
||||
name: 'topics',
|
||||
limit: 9999,
|
||||
|
||||
display: function(s) { return s.label; },
|
||||
templates: {
|
||||
notFound: function(s) {
|
||||
return Hogan.compile(topicheader + $('#topicSearchTemplate').html()).render({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
typeImageURL: Metamaps.Erb['icons/wildcard.png'],
|
||||
rtype: "noresult"
|
||||
});
|
||||
},
|
||||
header: topicheader,
|
||||
suggestion: function(s) {
|
||||
return Hogan.compile($('#topicSearchTemplate').html()).render(s);
|
||||
},
|
||||
},
|
||||
source: new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: '/search/topics',
|
||||
prepare: function(query, settings) {
|
||||
settings.url += '?term=' + query;
|
||||
if (Metamaps.Active.Mapper && self.limitTopicsToMe) {
|
||||
settings.url += "&user=" + Metamaps.Active.Mapper.id.toString();
|
||||
}
|
||||
return settings;
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
var maps = {
|
||||
name: 'maps',
|
||||
limit: 9999,
|
||||
display: function(s) { return s.label; },
|
||||
templates: {
|
||||
notFound: function(s) {
|
||||
return Hogan.compile(mapheader + $('#mapSearchTemplate').html()).render({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
rtype: "noresult"
|
||||
});
|
||||
},
|
||||
header: mapheader,
|
||||
suggestion: function(s) {
|
||||
return Hogan.compile($('#mapSearchTemplate').html()).render(s);
|
||||
},
|
||||
},
|
||||
source: new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: '/search/maps',
|
||||
prepare: function(query, settings) {
|
||||
settings.url += '?term=' + query;
|
||||
if (Metamaps.Active.Mapper && self.limitMapsToMe) {
|
||||
settings.url += "&user=" + Metamaps.Active.Mapper.id.toString();
|
||||
}
|
||||
return settings;
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
var mappers = {
|
||||
name: 'mappers',
|
||||
limit: 9999,
|
||||
display: function(s) { return s.label; },
|
||||
templates: {
|
||||
notFound: function(s) {
|
||||
return Hogan.compile(mapperheader + $('#mapperSearchTemplate').html()).render({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
rtype: "noresult",
|
||||
profile: Metamaps.Erb['user.png']
|
||||
});
|
||||
},
|
||||
header: mapperheader,
|
||||
suggestion: function(s) {
|
||||
return Hogan.compile($('#mapperSearchTemplate').html()).render(s);
|
||||
},
|
||||
},
|
||||
source: new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: '/search/mappers?term=%QUERY',
|
||||
wildcard: '%QUERY',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
// Take all that crazy setup data and put it together into one beautiful typeahead call!
|
||||
$('.sidebarSearchField').typeahead(
|
||||
{
|
||||
highlight: true,
|
||||
},
|
||||
[topics, maps, mappers]
|
||||
);
|
||||
|
||||
//Set max height of the search results box to prevent it from covering bottom left footer
|
||||
$('.sidebarSearchField').bind('typeahead:render', function (event) {
|
||||
self.initSearchOptions();
|
||||
self.hideLoader();
|
||||
var h = $(window).height();
|
||||
$(".tt-dropdown-menu").css('max-height', h - 100);
|
||||
if (self.limitTopicsToMe) {
|
||||
$('#limitTopicsToMe').prop('checked', true);
|
||||
}
|
||||
if (self.limitMapsToMe) {
|
||||
$('#limitMapsToMe').prop('checked', true);
|
||||
}
|
||||
});
|
||||
$(window).resize(function () {
|
||||
var h = $(window).height();
|
||||
$(".tt-dropdown-menu").css('max-height', h - 100);
|
||||
});
|
||||
|
||||
// tell the autocomplete to launch a new tab with the topic, map, or mapper you clicked on
|
||||
$('.sidebarSearchField').bind('typeahead:select', self.handleResultClick);
|
||||
|
||||
// don't do it, if they clicked on a 'addToMap' button
|
||||
$('.sidebarSearch button.addToMap').click(function (event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// make sure that when you click on 'limit to me' or 'toggle section' it works
|
||||
$('.sidebarSearchField.tt-input').keyup(function(){
|
||||
if ($('.sidebarSearchField.tt-input').val() === '') {
|
||||
self.hideLoader();
|
||||
} else {
|
||||
self.showLoader();
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
handleResultClick: function (event, datum, dataset) {
|
||||
var self = Metamaps.GlobalUI.Search;
|
||||
|
||||
self.hideLoader();
|
||||
|
||||
if (["topic", "map", "mapper"].indexOf(datum.rtype) !== -1) {
|
||||
self.close(0, true);
|
||||
var win;
|
||||
if (datum.rtype == "topic") {
|
||||
Metamaps.Router.topics(datum.id);
|
||||
} else if (datum.rtype == "map") {
|
||||
Metamaps.Router.maps(datum.id);
|
||||
} else if (datum.rtype == "mapper") {
|
||||
Metamaps.Router.explore("mapper", datum.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
initSearchOptions: function () {
|
||||
var self = Metamaps.GlobalUI.Search;
|
||||
|
||||
function toggleResultSet(set) {
|
||||
var s = $('.tt-dataset-' + set + ' .tt-suggestion, .tt-dataset-' + set + ' .resultnoresult');
|
||||
if (s.is(':visible')) {
|
||||
s.hide();
|
||||
$(this).removeClass('minimizeResults').addClass('maximizeResults');
|
||||
} else {
|
||||
s.show();
|
||||
$(this).removeClass('maximizeResults').addClass('minimizeResults');
|
||||
}
|
||||
}
|
||||
|
||||
$('.limitToMe').unbind().bind("change", function (e) {
|
||||
if ($(this).attr('id') == 'limitTopicsToMe') {
|
||||
self.limitTopicsToMe = !self.limitTopicsToMe;
|
||||
}
|
||||
if ($(this).attr('id') == 'limitMapsToMe') {
|
||||
self.limitMapsToMe = !self.limitMapsToMe;
|
||||
}
|
||||
|
||||
// set the value of the search equal to itself to retrigger the
|
||||
// autocomplete event
|
||||
var searchQuery = $('.sidebarSearchField.tt-input').val();
|
||||
$(".sidebarSearchField").typeahead('val', '')
|
||||
.typeahead('val', searchQuery);
|
||||
});
|
||||
|
||||
// when the user clicks minimize section, hide the results for that section
|
||||
$('.minimizeMapperResults').unbind().click(function (e) {
|
||||
toggleResultSet.call(this, 'mappers');
|
||||
});
|
||||
$('.minimizeTopicResults').unbind().click(function (e) {
|
||||
toggleResultSet.call(this, 'topics');
|
||||
});
|
||||
$('.minimizeMapResults').unbind().click(function (e) {
|
||||
toggleResultSet.call(this, 'maps');
|
||||
});
|
||||
},
|
||||
hideLoader: function () {
|
||||
$('#searchLoading').hide();
|
||||
},
|
||||
showLoader: function () {
|
||||
$('#searchLoading').show();
|
||||
}
|
||||
};
|
|
@ -1,122 +0,0 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Listeners.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.Control
|
||||
* - Metamaps.JIT
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
Metamaps.Listeners = {
|
||||
init: function () {
|
||||
var self = this
|
||||
$(document).on('keydown', function (e) {
|
||||
if (!(Metamaps.Active.Map || Metamaps.Active.Topic)) return
|
||||
|
||||
switch (e.which) {
|
||||
case 13: // if enter key is pressed
|
||||
Metamaps.JIT.enterKeyHandler()
|
||||
e.preventDefault()
|
||||
break
|
||||
case 27: // if esc key is pressed
|
||||
Metamaps.JIT.escKeyHandler()
|
||||
break
|
||||
case 65: // if a or A is pressed
|
||||
if (e.ctrlKey) {
|
||||
Metamaps.Control.deselectAllNodes()
|
||||
Metamaps.Control.deselectAllEdges()
|
||||
|
||||
e.preventDefault()
|
||||
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
|
||||
Metamaps.Control.selectNode(n, e)
|
||||
})
|
||||
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
}
|
||||
|
||||
break
|
||||
case 68: // if d or D is pressed
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault()
|
||||
Metamaps.Control.deleteSelected()
|
||||
}
|
||||
break
|
||||
case 69: // if e or E is pressed
|
||||
if (e.ctrlKey && Metamaps.Active.Map) {
|
||||
e.preventDefault()
|
||||
Metamaps.JIT.zoomExtents(null, Metamaps.Visualize.mGraph.canvas)
|
||||
break
|
||||
}
|
||||
if (e.altKey && Metamaps.Active.Topic) {
|
||||
e.preventDefault()
|
||||
|
||||
if (Metamaps.Active.Topic) {
|
||||
self.centerAndReveal(Metamaps.Selected.Nodes, {
|
||||
center: true,
|
||||
reveal: false
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
case 72: // if h or H is pressed
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault()
|
||||
Metamaps.Control.hideSelectedNodes()
|
||||
Metamaps.Control.hideSelectedEdges()
|
||||
}
|
||||
break
|
||||
case 77: // if m or M is pressed
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault()
|
||||
Metamaps.Control.removeSelectedNodes()
|
||||
Metamaps.Control.removeSelectedEdges()
|
||||
}
|
||||
break
|
||||
case 82: // if r or R is pressed
|
||||
if (e.altKey && Metamaps.Active.Topic) {
|
||||
e.preventDefault()
|
||||
self.centerAndReveal(Metamaps.Selected.Nodes, {
|
||||
center: false,
|
||||
reveal: true
|
||||
})
|
||||
}
|
||||
break
|
||||
case 84: // if t or T is pressed
|
||||
if (e.altKey && Metamaps.Active.Topic) {
|
||||
e.preventDefault()
|
||||
self.centerAndReveal(Metamaps.Selected.Nodes, {
|
||||
center: true,
|
||||
reveal: true
|
||||
})
|
||||
}
|
||||
break
|
||||
default:
|
||||
// console.log(e.which)
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
$(window).resize(function () {
|
||||
if (Metamaps.Visualize && Metamaps.Visualize.mGraph) Metamaps.Visualize.mGraph.canvas.resize($(window).width(), $(window).height())
|
||||
if ((Metamaps.Active.Map || Metamaps.Active.Topic) && Metamaps.Famous && Metamaps.Famous.maps.surf) Metamaps.Famous.maps.reposition()
|
||||
if (Metamaps.Active.Map && Metamaps.Realtime.inConversation) Metamaps.Realtime.positionVideos()
|
||||
Metamaps.Mobile.resizeTitle()
|
||||
})
|
||||
},
|
||||
centerAndReveal: function(nodes, opts) {
|
||||
if (nodes.length < 1) return
|
||||
var node = nodes[nodes.length - 1]
|
||||
if (opts.center && opts.reveal) {
|
||||
Metamaps.Topic.centerOn(node.id, function() {
|
||||
Metamaps.Topic.fetchRelatives(nodes)
|
||||
})
|
||||
} else if (opts.center) {
|
||||
Metamaps.Topic.centerOn(node.id)
|
||||
} else if (opts.reveal) {
|
||||
Metamaps.Topic.fetchRelatives(nodes)
|
||||
}
|
||||
}
|
||||
}; // end Metamaps.Listeners
|
|
@ -1,754 +0,0 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Map.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.AutoLayout
|
||||
* - Metamaps.Create
|
||||
* - Metamaps.Erb
|
||||
* - 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'
|
||||
},
|
||||
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
|
||||
})
|
||||
|
||||
$('.starMap').click(function () {
|
||||
if ($(this).is('.starred')) self.unstar()
|
||||
else self.star()
|
||||
})
|
||||
|
||||
$('.sidebarFork').click(function () {
|
||||
self.fork()
|
||||
})
|
||||
|
||||
Metamaps.GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html()
|
||||
|
||||
self.updateStar()
|
||||
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.Collaborators = new bb.MapperCollection(data.collaborators)
|
||||
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.Stars = data.stars
|
||||
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')
|
||||
}
|
||||
|
||||
Metamaps.Map.updateStar()
|
||||
|
||||
// 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()
|
||||
|
||||
// for mobile
|
||||
$('#header_content').html(map.get('name'))
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/maps/' + id + '/contains.json',
|
||||
success: start
|
||||
})
|
||||
},
|
||||
end: function () {
|
||||
if (Metamaps.Active.Map) {
|
||||
$('.wrapper').removeClass('canEditMap commonsMap')
|
||||
Metamaps.AutoLayout.resetSpiral()
|
||||
|
||||
$('.rightclickmenu').remove()
|
||||
Metamaps.TopicCard.hideCard()
|
||||
Metamaps.SynapseCard.hideCard()
|
||||
Metamaps.Create.newTopic.hide(true) // true means force (and override pinned)
|
||||
Metamaps.Create.newSynapse.hide()
|
||||
Metamaps.Filter.close()
|
||||
Metamaps.Map.InfoBox.close()
|
||||
Metamaps.Realtime.endActiveMap()
|
||||
}
|
||||
},
|
||||
updateStar: function () {
|
||||
if (!Metamaps.Active.Mapper || !Metamaps.Stars) return
|
||||
// update the star/unstar icon
|
||||
if (Metamaps.Stars.find(function (s) { return s.user_id === Metamaps.Active.Mapper.id })) {
|
||||
$('.starMap').addClass('starred')
|
||||
$('.starMap .tooltipsAbove').html('Unstar')
|
||||
} else {
|
||||
$('.starMap').removeClass('starred')
|
||||
$('.starMap .tooltipsAbove').html('Star')
|
||||
}
|
||||
},
|
||||
star: function () {
|
||||
var self = Metamaps.Map
|
||||
|
||||
if (!Metamaps.Active.Map) return
|
||||
$.post('/maps/' + Metamaps.Active.Map.id + '/star')
|
||||
Metamaps.Stars.push({ user_id: Metamaps.Active.Mapper.id, map_id: Metamaps.Active.Map.id })
|
||||
Metamaps.Maps.Starred.add(Metamaps.Active.Map)
|
||||
Metamaps.GlobalUI.notifyUser('Map is now starred')
|
||||
self.updateStar()
|
||||
},
|
||||
unstar: function () {
|
||||
var self = Metamaps.Map
|
||||
|
||||
if (!Metamaps.Active.Map) return
|
||||
$.post('/maps/' + Metamaps.Active.Map.id + '/unstar')
|
||||
Metamaps.Stars = Metamaps.Stars.filter(function (s) { return s.user_id != Metamaps.Active.Mapper.id })
|
||||
Metamaps.Maps.Starred.remove(Metamaps.Active.Map)
|
||||
self.updateStar()
|
||||
},
|
||||
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.')
|
||||
},
|
||||
cantEditNow: 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')
|
||||
},
|
||||
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 = confirm(confirmString)
|
||||
if (c) {
|
||||
Metamaps.Router.maps(Metamaps.Active.Map.id)
|
||||
}
|
||||
},
|
||||
editedByActiveMapper: function () {
|
||||
if (Metamaps.Active.Mapper) {
|
||||
Metamaps.Mappers.add(Metamaps.Active.Mapper)
|
||||
}
|
||||
},
|
||||
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 += "<a href='" + imageData.encoded_image + "' "
|
||||
downloadMessage += "download='metamap-" + map.id + '-' + mapName + '-' + today + ".png'>DOWNLOAD</a>"
|
||||
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: "<div class='tooltips'>As the creator, you can change the permission of this map, and the permission of all the topics and synapses you have authority to change will change as well.</div>",
|
||||
nameHTML: '<span class="best_in_place best_in_place_name" id="best_in_place_map_{{id}}_name" data-url="/maps/{{id}}" data-object="map" data-attribute="name" data-type="textarea" data-activator="#mapInfoName">{{name}}</span>',
|
||||
descHTML: '<span class="best_in_place best_in_place_desc" id="best_in_place_map_{{id}}_desc" data-url="/maps/{{id}}" data-object="map" data-attribute="desc" data-nil="Click to add description..." data-type="textarea" data-activator="#mapInfoDesc">{{desc}}</span>',
|
||||
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())
|
||||
|
||||
var querystring = window.location.search.replace(/^\?/, '')
|
||||
if (querystring == 'new') {
|
||||
self.open()
|
||||
$('.mapInfoBox').addClass('mapRequestTitle')
|
||||
}
|
||||
},
|
||||
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', 'topic_count', 'synapse_count')
|
||||
|
||||
var isCreator = map.authorizePermissionChange(Metamaps.Active.Mapper)
|
||||
var canEdit = map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var relevantPeople = map.get('permission') === 'commons' ? Metamaps.Mappers : Metamaps.Collaborators
|
||||
var shareable = map.get('permission') !== 'private'
|
||||
|
||||
obj['name'] = canEdit ? Hogan.compile(self.nameHTML).render({id: map.id, name: map.get('name')}) : map.get('name')
|
||||
obj['desc'] = canEdit ? Hogan.compile(self.descHTML).render({id: map.id, desc: map.get('desc')}) : map.get('desc')
|
||||
obj['map_creator_tip'] = isCreator ? self.changePermissionText : ''
|
||||
|
||||
obj['contributor_count'] = relevantPeople.length
|
||||
obj['contributors_class'] = relevantPeople.length > 1 ? 'multiple' : ''
|
||||
obj['contributors_class'] += relevantPeople.length === 2 ? ' mTwo' : ''
|
||||
obj['contributor_image'] = relevantPeople.length > 0 ? relevantPeople.models[0].get('image') : Metamaps.Erb['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('<div class="nameCounter forMap"></div>')
|
||||
|
||||
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')
|
||||
// mobile menu
|
||||
$('#header_content').html(name)
|
||||
$('.mapInfoBox').removeClass('mapRequestTitle')
|
||||
document.title = name + ' | Metamaps'
|
||||
})
|
||||
|
||||
$('.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()
|
||||
})
|
||||
|
||||
self.addTypeahead()
|
||||
},
|
||||
addTypeahead: function () {
|
||||
var self = Metamaps.Map.InfoBox
|
||||
|
||||
if (!Metamaps.Active.Map) return
|
||||
|
||||
// for autocomplete
|
||||
var collaborators = {
|
||||
name: 'collaborators',
|
||||
limit: 9999,
|
||||
display: function(s) { return s.label; },
|
||||
templates: {
|
||||
notFound: function(s) {
|
||||
return Hogan.compile($('#collaboratorSearchTemplate').html()).render({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
rtype: "noresult",
|
||||
profile: Metamaps.Erb['user.png'],
|
||||
});
|
||||
},
|
||||
suggestion: function(s) {
|
||||
return Hogan.compile($('#collaboratorSearchTemplate').html()).render(s);
|
||||
},
|
||||
},
|
||||
source: new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: '/search/mappers?term=%QUERY',
|
||||
wildcard: '%QUERY',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// for adding map collaborators, who will have edit rights
|
||||
if (Metamaps.Active.Mapper && Metamaps.Active.Mapper.id === Metamaps.Active.Map.get('user_id')) {
|
||||
$('.collaboratorSearchField').typeahead(
|
||||
{
|
||||
highlight: false,
|
||||
},
|
||||
[collaborators]
|
||||
)
|
||||
$('.collaboratorSearchField').bind('typeahead:select', self.handleResultClick)
|
||||
$('.mapContributors .removeCollaborator').click(function () {
|
||||
self.removeCollaborator(parseInt($(this).data('id')))
|
||||
})
|
||||
}
|
||||
},
|
||||
removeCollaborator: function (collaboratorId) {
|
||||
var self = Metamaps.Map.InfoBox
|
||||
Metamaps.Collaborators.remove(Metamaps.Collaborators.get(collaboratorId))
|
||||
var mapperIds = Metamaps.Collaborators.models.map(function (mapper) { return mapper.id })
|
||||
$.post('/maps/' + Metamaps.Active.Map.id + '/access', { access: mapperIds })
|
||||
self.updateNumbers()
|
||||
},
|
||||
addCollaborator: function (newCollaboratorId) {
|
||||
var self = Metamaps.Map.InfoBox
|
||||
|
||||
if (Metamaps.Collaborators.get(newCollaboratorId)) {
|
||||
Metamaps.GlobalUI.notifyUser('That user already has access')
|
||||
return
|
||||
}
|
||||
|
||||
function callback(mapper) {
|
||||
Metamaps.Collaborators.add(mapper)
|
||||
var mapperIds = Metamaps.Collaborators.models.map(function (mapper) { return mapper.id })
|
||||
$.post('/maps/' + Metamaps.Active.Map.id + '/access', { access: mapperIds })
|
||||
var name = Metamaps.Collaborators.get(newCollaboratorId).get('name')
|
||||
Metamaps.GlobalUI.notifyUser(name + ' will be notified by email')
|
||||
self.updateNumbers()
|
||||
}
|
||||
|
||||
$.getJSON('/users/' + newCollaboratorId + '.json', callback)
|
||||
},
|
||||
handleResultClick: function (event, item) {
|
||||
var self = Metamaps.Map.InfoBox
|
||||
|
||||
self.addCollaborator(item.id)
|
||||
$('.collaboratorSearchField').typeahead('val', '')
|
||||
},
|
||||
updateNameDescPerm: function (name, desc, perm) {
|
||||
$('.mapInfoBox').removeClass('mapRequestTitle')
|
||||
$('.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 relevantPeople = Metamaps.Active.Map.get('permission') === 'commons' ? Metamaps.Mappers : Metamaps.Collaborators
|
||||
var activeMapperIsCreator = Metamaps.Active.Mapper && Metamaps.Active.Mapper.id === Metamaps.Active.Map.get('user_id')
|
||||
var string = ''
|
||||
string += '<ul>'
|
||||
|
||||
relevantPeople.each(function (m) {
|
||||
var isCreator = Metamaps.Active.Map.get('user_id') === m.get('id')
|
||||
string += '<li><a href="/explore/mapper/' + m.get('id') + '">' + '<img class="rtUserImage" width="25" height="25" src="' + m.get('image') + '" />' + m.get('name')
|
||||
if (isCreator) string += ' (creator)'
|
||||
string += '</a>'
|
||||
if (activeMapperIsCreator && !isCreator) string += '<span class="removeCollaborator" data-id="' + m.get('id') + '"></span>'
|
||||
string += '</li>'
|
||||
})
|
||||
|
||||
string += '</ul>'
|
||||
|
||||
if (activeMapperIsCreator) {
|
||||
string += '<div class="collabSearchField"><span class="addCollab"></span><input class="collaboratorSearchField" placeholder="Add a collaborator!"></input></div>'
|
||||
}
|
||||
return string
|
||||
},
|
||||
updateNumbers: function () {
|
||||
if (!Metamaps.Active.Map) return
|
||||
|
||||
var self = Metamaps.Map.InfoBox
|
||||
var mapper = Metamaps.Active.Mapper
|
||||
var relevantPeople = Metamaps.Active.Map.get('permission') === 'commons' ? Metamaps.Mappers : Metamaps.Collaborators
|
||||
|
||||
var contributors_class = ''
|
||||
if (relevantPeople.length === 2) contributors_class = 'multiple mTwo'
|
||||
else if (relevantPeople.length > 2) contributors_class = 'multiple'
|
||||
|
||||
var contributors_image = Metamaps.Erb['user.png']
|
||||
if (relevantPeople.length > 0) {
|
||||
// get the first contributor and use their image
|
||||
contributors_image = relevantPeople.models[0].get('image')
|
||||
}
|
||||
$('.mapContributors img').attr('src', contributors_image).removeClass('multiple mTwo').addClass(contributors_class)
|
||||
$('.mapContributors span').text(relevantPeople.length)
|
||||
$('.mapContributors .tip').html(self.createContributorList())
|
||||
self.addTypeahead()
|
||||
$('.mapContributors .tip').unbind().click(function (event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
$('.mapTopics').text(Metamaps.Topics.length)
|
||||
$('.mapSynapses').text(Metamaps.Synapses.length)
|
||||
|
||||
$('.mapEditedAt').html('<span>Last edited: </span>' + 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('<ul class="permissionSelect"><li class="public"></li><li class="private"></li></ul>')
|
||||
} else if ($(this).hasClass('public')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="private"></li></ul>')
|
||||
} else if ($(this).hasClass('private')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="public"></li></ul>')
|
||||
}
|
||||
$('.mapPermission .permissionSelect li').click(self.selectPermission)
|
||||
event.stopPropagation()
|
||||
}
|
||||
},
|
||||
hidePermissionSelect: function () {
|
||||
var self = 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')
|
||||
Metamaps.Active.Map.save({
|
||||
permission: permission
|
||||
})
|
||||
Metamaps.Active.Map.updateMapWrapper()
|
||||
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)
|
||||
Metamaps.Maps.Shared.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
|
|
@ -1,20 +0,0 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Mapper.js.erb
|
||||
*
|
||||
* Dependencies: none!
|
||||
*/
|
||||
|
||||
Metamaps.Mapper = {
|
||||
// this function is to retrieve a mapper JSON object from the database
|
||||
// @param id = the id of the mapper to retrieve
|
||||
get: function (id, callback) {
|
||||
return $.ajax({
|
||||
url: '/users/' + id + '.json',
|
||||
success: function (data) {
|
||||
callback(new Metamaps.Backbone.Mapper(data))
|
||||
}
|
||||
})
|
||||
}
|
||||
}; // end Metamaps.Mapper
|
|
@ -1,245 +0,0 @@
|
|||
/* global Metamaps, Backbone, $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Router.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.GlobalUI
|
||||
* - Metamaps.JIT
|
||||
* - Metamaps.Loading
|
||||
* - Metamaps.Map
|
||||
* - Metamaps.Maps
|
||||
* - Metamaps.Topic
|
||||
* - Metamaps.Views
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
|
||||
;(function () {
|
||||
var Router = Backbone.Router.extend({
|
||||
routes: {
|
||||
'': 'home', // #home
|
||||
'explore/:section': 'explore', // #explore/active
|
||||
'explore/:section/:id': 'explore', // #explore/mapper/1234
|
||||
'maps/:id': 'maps' // #maps/7
|
||||
},
|
||||
home: function () {
|
||||
clearTimeout(Metamaps.Router.timeoutId)
|
||||
|
||||
if (Metamaps.Active.Mapper) document.title = 'Explore Active Maps | Metamaps'
|
||||
else document.title = 'Home | Metamaps'
|
||||
|
||||
Metamaps.Router.currentSection = ''
|
||||
Metamaps.Router.currentPage = ''
|
||||
$('.wrapper').removeClass('mapPage topicPage')
|
||||
|
||||
var classes = Metamaps.Active.Mapper ? 'homePage explorePage' : 'homePage'
|
||||
$('.wrapper').addClass(classes)
|
||||
|
||||
var navigate = function () {
|
||||
Metamaps.Router.timeoutId = setTimeout(function () {
|
||||
Metamaps.Router.navigate('')
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// all this only for the logged in home page
|
||||
if (Metamaps.Active.Mapper) {
|
||||
$('.homeButton a').attr('href', '/')
|
||||
Metamaps.GlobalUI.hideDiv('#yield')
|
||||
|
||||
Metamaps.GlobalUI.showDiv('#explore')
|
||||
|
||||
Metamaps.Views.exploreMaps.setCollection(Metamaps.Maps.Active)
|
||||
if (Metamaps.Maps.Active.length === 0) {
|
||||
Metamaps.Maps.Active.getMaps(navigate) // this will trigger an explore maps render
|
||||
} else {
|
||||
Metamaps.Views.exploreMaps.render(navigate)
|
||||
}
|
||||
} else {
|
||||
// logged out home page
|
||||
Metamaps.GlobalUI.hideDiv('#explore')
|
||||
Metamaps.GlobalUI.showDiv('#yield')
|
||||
Metamaps.Router.timeoutId = setTimeout(navigate, 500)
|
||||
}
|
||||
|
||||
Metamaps.GlobalUI.hideDiv('#infovis')
|
||||
Metamaps.GlobalUI.hideDiv('#instructions')
|
||||
Metamaps.Map.end()
|
||||
Metamaps.Topic.end()
|
||||
Metamaps.Active.Map = null
|
||||
Metamaps.Active.Topic = null
|
||||
},
|
||||
explore: function (section, id) {
|
||||
clearTimeout(Metamaps.Router.timeoutId)
|
||||
|
||||
// just capitalize the variable section
|
||||
// either 'featured', 'mapper', or 'active'
|
||||
var capitalize = section.charAt(0).toUpperCase() + section.slice(1)
|
||||
|
||||
if (section === 'shared' || section === 'featured' || section === 'active' || section === 'starred') {
|
||||
document.title = 'Explore ' + capitalize + ' Maps | Metamaps'
|
||||
} else if (section === 'mapper') {
|
||||
$.ajax({
|
||||
url: '/users/' + id + '.json',
|
||||
success: function (response) {
|
||||
document.title = response.name + ' | Metamaps'
|
||||
},
|
||||
error: function () {}
|
||||
})
|
||||
} else if (section === 'mine') {
|
||||
document.title = 'Explore My Maps | Metamaps'
|
||||
}
|
||||
|
||||
if (Metamaps.Active.Mapper && section != 'mapper') $('.homeButton a').attr('href', '/explore/' + section)
|
||||
$('.wrapper').removeClass('homePage mapPage topicPage')
|
||||
$('.wrapper').addClass('explorePage')
|
||||
|
||||
Metamaps.Router.currentSection = 'explore'
|
||||
Metamaps.Router.currentPage = section
|
||||
|
||||
// this will mean it's a mapper page being loaded
|
||||
if (id) {
|
||||
if (Metamaps.Maps.Mapper.mapperId !== id) {
|
||||
// empty the collection if we are trying to load the maps
|
||||
// collection of a different mapper than we had previously
|
||||
Metamaps.Maps.Mapper.reset()
|
||||
Metamaps.Maps.Mapper.page = 1
|
||||
}
|
||||
Metamaps.Maps.Mapper.mapperId = id
|
||||
}
|
||||
|
||||
Metamaps.Views.exploreMaps.setCollection(Metamaps.Maps[capitalize])
|
||||
|
||||
var navigate = function () {
|
||||
var path = '/explore/' + Metamaps.Router.currentPage
|
||||
|
||||
// alter url if for mapper profile page
|
||||
if (Metamaps.Router.currentPage === 'mapper') {
|
||||
path += '/' + Metamaps.Maps.Mapper.mapperId
|
||||
}
|
||||
|
||||
Metamaps.Router.navigate(path)
|
||||
}
|
||||
var navigateTimeout = function () {
|
||||
Metamaps.Router.timeoutId = setTimeout(navigate, 300)
|
||||
}
|
||||
if (Metamaps.Maps[capitalize].length === 0) {
|
||||
Metamaps.Loading.show()
|
||||
setTimeout(function () {
|
||||
Metamaps.Maps[capitalize].getMaps(navigate) // this will trigger an explore maps render
|
||||
}, 300) // wait 300 milliseconds till the other animations are done to do the fetch
|
||||
} else {
|
||||
if (id) {
|
||||
Metamaps.Views.exploreMaps.fetchUserThenRender(navigateTimeout)
|
||||
} else {
|
||||
Metamaps.Views.exploreMaps.render(navigateTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
Metamaps.GlobalUI.showDiv('#explore')
|
||||
Metamaps.GlobalUI.hideDiv('#yield')
|
||||
Metamaps.GlobalUI.hideDiv('#infovis')
|
||||
Metamaps.GlobalUI.hideDiv('#instructions')
|
||||
Metamaps.Map.end()
|
||||
Metamaps.Topic.end()
|
||||
Metamaps.Active.Map = null
|
||||
Metamaps.Active.Topic = null
|
||||
},
|
||||
maps: function (id) {
|
||||
clearTimeout(Metamaps.Router.timeoutId)
|
||||
|
||||
document.title = 'Map ' + id + ' | Metamaps'
|
||||
|
||||
Metamaps.Router.currentSection = 'map'
|
||||
Metamaps.Router.currentPage = id
|
||||
|
||||
$('.wrapper').removeClass('homePage explorePage topicPage')
|
||||
$('.wrapper').addClass('mapPage')
|
||||
// another class will be added to wrapper if you
|
||||
// can edit this map '.canEditMap'
|
||||
|
||||
Metamaps.GlobalUI.hideDiv('#yield')
|
||||
Metamaps.GlobalUI.hideDiv('#explore')
|
||||
|
||||
// clear the visualization, if there was one, before showing its div again
|
||||
if (Metamaps.Visualize.mGraph) {
|
||||
Metamaps.Visualize.mGraph.graph.empty()
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas)
|
||||
}
|
||||
Metamaps.GlobalUI.showDiv('#infovis')
|
||||
Metamaps.Topic.end()
|
||||
Metamaps.Active.Topic = null
|
||||
|
||||
Metamaps.Loading.show()
|
||||
Metamaps.Map.end()
|
||||
Metamaps.Map.launch(id)
|
||||
},
|
||||
topics: function (id) {
|
||||
clearTimeout(Metamaps.Router.timeoutId)
|
||||
|
||||
document.title = 'Topic ' + id + ' | Metamaps'
|
||||
|
||||
Metamaps.Router.currentSection = 'topic'
|
||||
Metamaps.Router.currentPage = id
|
||||
|
||||
$('.wrapper').removeClass('homePage explorePage mapPage')
|
||||
$('.wrapper').addClass('topicPage')
|
||||
|
||||
Metamaps.GlobalUI.hideDiv('#yield')
|
||||
Metamaps.GlobalUI.hideDiv('#explore')
|
||||
|
||||
// clear the visualization, if there was one, before showing its div again
|
||||
if (Metamaps.Visualize.mGraph) {
|
||||
Metamaps.Visualize.mGraph.graph.empty()
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas)
|
||||
}
|
||||
Metamaps.GlobalUI.showDiv('#infovis')
|
||||
Metamaps.Map.end()
|
||||
Metamaps.Active.Map = null
|
||||
|
||||
Metamaps.Topic.end()
|
||||
Metamaps.Topic.launch(id)
|
||||
}
|
||||
})
|
||||
|
||||
Metamaps.Router = new Router()
|
||||
Metamaps.Router.currentPage = ''
|
||||
Metamaps.Router.currentSection = undefined
|
||||
Metamaps.Router.timeoutId = undefined
|
||||
|
||||
Metamaps.Router.intercept = function (evt) {
|
||||
var segments
|
||||
|
||||
var href = {
|
||||
prop: $(this).prop('href'),
|
||||
attr: $(this).attr('href')
|
||||
}
|
||||
var root = window.location.protocol + '//' + window.location.host + Backbone.history.options.root
|
||||
|
||||
if (href.prop && href.prop === root) href.attr = ''
|
||||
|
||||
if (href.prop && href.prop.slice(0, root.length) === root) {
|
||||
evt.preventDefault()
|
||||
|
||||
segments = href.attr.split('/')
|
||||
segments.splice(0, 1) // pop off the element created by the first /
|
||||
|
||||
if (href.attr === '') {
|
||||
Metamaps.Router.home()
|
||||
} else {
|
||||
Metamaps.Router[segments[0]](segments[1], segments[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Metamaps.Router.init = function () {
|
||||
Backbone.history.start({
|
||||
silent: true,
|
||||
pushState: true,
|
||||
root: '/'
|
||||
})
|
||||
$(document).on('click', 'a[data-router="true"]', Metamaps.Router.intercept)
|
||||
}
|
||||
})()
|
|
@ -1,87 +0,0 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Views.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Loading
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.ReactComponents
|
||||
*/
|
||||
|
||||
Metamaps.Views = {
|
||||
exploreMaps: {
|
||||
setCollection: function (collection) {
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
if (self.collection) {
|
||||
self.collection.off('add', self.render)
|
||||
self.collection.off('successOnFetch', self.handleSuccess)
|
||||
self.collection.off('errorOnFetch', self.handleError)
|
||||
}
|
||||
self.collection = collection
|
||||
self.collection.on('add', self.render)
|
||||
self.collection.on('successOnFetch', self.handleSuccess)
|
||||
self.collection.on('errorOnFetch', self.handleError)
|
||||
},
|
||||
render: function (mapperObj, cb) {
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
if (typeof mapperObj === 'function') {
|
||||
cb = mapperObj
|
||||
mapperObj = null
|
||||
}
|
||||
|
||||
var exploreObj = {
|
||||
currentUser: Metamaps.Active.Mapper,
|
||||
section: self.collection.id,
|
||||
displayStyle: 'grid',
|
||||
maps: self.collection,
|
||||
moreToLoad: self.collection.page != 'loadedAll',
|
||||
user: mapperObj,
|
||||
loadMore: self.loadMore
|
||||
}
|
||||
ReactDOM.render(
|
||||
React.createElement(Metamaps.ReactComponents.Maps, exploreObj),
|
||||
document.getElementById('explore')
|
||||
)
|
||||
|
||||
if (cb) cb()
|
||||
Metamaps.Loading.hide()
|
||||
},
|
||||
loadMore: function () {
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
if (self.collection.page != "loadedAll") {
|
||||
self.collection.getMaps()
|
||||
}
|
||||
else self.render()
|
||||
},
|
||||
handleSuccess: function (cb) {
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
if (self.collection && self.collection.id === 'mapper') {
|
||||
self.fetchUserThenRender(cb)
|
||||
} else {
|
||||
self.render(cb)
|
||||
}
|
||||
},
|
||||
handleError: function () {
|
||||
console.log('error loading maps!') // TODO
|
||||
},
|
||||
fetchUserThenRender: function (cb) {
|
||||
var self = Metamaps.Views.exploreMaps
|
||||
|
||||
// first load the mapper object and then call the render function
|
||||
$.ajax({
|
||||
url: '/users/' + self.collection.mapperId + '/details.json',
|
||||
success: function (response) {
|
||||
self.render(response, cb)
|
||||
},
|
||||
error: function () {
|
||||
self.render(cb)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/* global Metamaps */
|
||||
|
||||
/*
|
||||
* Metamaps.js.erb
|
||||
*/
|
||||
|
||||
// TODO eliminate these 5 top-level variables
|
||||
Metamaps.panningInt = null
|
||||
Metamaps.tempNode = null
|
||||
Metamaps.tempInit = false
|
||||
Metamaps.tempNode2 = null
|
||||
Metamaps.VERSION = '<%= METAMAPS_VERSION %>'
|
||||
|
||||
/* erb variables from rails */
|
||||
Metamaps.Erb = {}
|
||||
Metamaps.Erb['REALTIME_SERVER'] = '<%= ENV['REALTIME_SERVER'] %>'
|
||||
Metamaps.Erb['junto_spinner_darkgrey.gif'] = '<%= asset_path('junto_spinner_darkgrey.gif') %>'
|
||||
Metamaps.Erb['user.png'] = '<%= asset_path('user.png') %>'
|
||||
Metamaps.Erb['icons/wildcard.png'] = '<%= asset_path('icons/wildcard.png') %>'
|
||||
Metamaps.Erb['topic_description_signifier.png'] = '<%= asset_path('topic_description_signifier.png') %>'
|
||||
Metamaps.Erb['topic_link_signifier.png'] = '<%= asset_path('topic_link_signifier.png') %>'
|
||||
Metamaps.Erb['synapse16.png'] = '<%= asset_path('synapse16.png') %>'
|
||||
Metamaps.Metacodes = <%= Metacode.all.to_json.gsub(%r[(icon.*?)(\"},)], '\1?purple=stupid\2').html_safe %>
|
||||
|
||||
Metamaps.Settings = {
|
||||
embed: false, // indicates that the app is on a page that is optimized for embedding in iFrames on other web pages
|
||||
sandbox: false, // puts the app into a mode (when true) where it only creates data locally, and isn't writing it to the database
|
||||
colors: {
|
||||
background: '#344A58',
|
||||
synapses: {
|
||||
normal: '#888888',
|
||||
hover: '#888888',
|
||||
selected: '#FFFFFF'
|
||||
},
|
||||
topics: {
|
||||
selected: '#FFFFFF'
|
||||
},
|
||||
labels: {
|
||||
background: '#18202E',
|
||||
text: '#DDD'
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Metamaps.Touch = {
|
||||
touchPos: null, // this stores the x and y values of a current touch event
|
||||
touchDragNode: null // this stores a reference to a JIT node that is being dragged
|
||||
}
|
||||
|
||||
Metamaps.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
|
||||
}
|
||||
|
||||
Metamaps.Selected = {
|
||||
reset: function () {
|
||||
var self = Metamaps.Selected
|
||||
|
||||
self.Nodes = []
|
||||
self.Edges = []
|
||||
},
|
||||
Nodes: [],
|
||||
Edges: []
|
||||
}
|
|
@ -1,343 +0,0 @@
|
|||
Metamaps.Views = Metamaps.Views || {};
|
||||
|
||||
Metamaps.Views.chatView = (function () {
|
||||
var
|
||||
chatView,
|
||||
linker = new Autolinker({ newWindow: true, truncate: 50, email: false, phone: false, twitter: false });
|
||||
|
||||
var Private = {
|
||||
messageHTML: "<div class='chat-message'>" +
|
||||
"<div class='chat-message-user'><img src='{{ user_image }}' title='{{user_name }}'/></div>" +
|
||||
"<div class='chat-message-text'>{{ message }}</div>" +
|
||||
"<div class='chat-message-time'>{{ timestamp }}</div>" +
|
||||
"<div class='clearfloat'></div>" +
|
||||
"</div>",
|
||||
participantHTML: "<div class='participant participant-{{ id }} {{ selfClass }}'>" +
|
||||
"<div class='chat-participant-image'><img src='{{ image }}' style='border: 2px solid {{ color }};' /></div>" +
|
||||
"<div class='chat-participant-name'>{{ username }} {{ selfName }}</div>" +
|
||||
"<button type='button' class='button chat-participant-invite-call' onclick='Metamaps.Realtime.inviteACall({{ id}});'></button>" +
|
||||
"<button type='button' class='button chat-participant-invite-join' onclick='Metamaps.Realtime.inviteToJoin({{ id}});'></button>" +
|
||||
"<span class='chat-participant-participating'><div class='green-dot'></div></span>" +
|
||||
"<div class='clearfloat'></div>" +
|
||||
"</div>",
|
||||
templates: function() {
|
||||
_.templateSettings = {
|
||||
interpolate: /\{\{(.+?)\}\}/g
|
||||
};
|
||||
this.messageTemplate = _.template(Private.messageHTML);
|
||||
|
||||
this.participantTemplate = _.template(Private.participantHTML);
|
||||
},
|
||||
createElements: function() {
|
||||
this.$unread = $('<div class="chat-unread"></div>');
|
||||
this.$button = $('<div class="chat-button"><div class="tooltips">Chat</div></div>');
|
||||
this.$messageInput = $('<textarea placeholder="Send a message..." class="chat-input"></textarea>');
|
||||
this.$juntoHeader = $('<div class="junto-header">PARTICIPANTS</div>');
|
||||
this.$videoToggle = $('<div class="video-toggle"></div>');
|
||||
this.$cursorToggle = $('<div class="cursor-toggle"></div>');
|
||||
this.$participants = $('<div class="participants"></div>');
|
||||
this.$conversationInProgress = $('<div class="conversation-live">LIVE <span class="call-action leave" onclick="Metamaps.Realtime.leaveCall();">LEAVE</span><span class="call-action join" onclick="Metamaps.Realtime.joinCall();">JOIN</span></div>');
|
||||
this.$chatHeader = $('<div class="chat-header">CHAT</div>');
|
||||
this.$soundToggle = $('<div class="sound-toggle"></div>');
|
||||
this.$messages = $('<div class="chat-messages"></div>');
|
||||
this.$container = $('<div class="chat-box"></div>');
|
||||
},
|
||||
attachElements: function() {
|
||||
this.$button.append(this.$unread);
|
||||
|
||||
this.$juntoHeader.append(this.$videoToggle);
|
||||
this.$juntoHeader.append(this.$cursorToggle);
|
||||
|
||||
this.$chatHeader.append(this.$soundToggle);
|
||||
|
||||
this.$participants.append(this.$conversationInProgress);
|
||||
|
||||
this.$container.append(this.$juntoHeader);
|
||||
this.$container.append(this.$participants);
|
||||
this.$container.append(this.$chatHeader);
|
||||
this.$container.append(this.$button);
|
||||
this.$container.append(this.$messages);
|
||||
this.$container.append(this.$messageInput);
|
||||
},
|
||||
addEventListeners: function() {
|
||||
var self = this;
|
||||
|
||||
this.participants.on('add', function (participant) {
|
||||
Private.addParticipant.call(self, participant);
|
||||
});
|
||||
|
||||
this.participants.on('remove', function (participant) {
|
||||
Private.removeParticipant.call(self, participant);
|
||||
});
|
||||
|
||||
this.$button.on('click', function () {
|
||||
Handlers.buttonClick.call(self);
|
||||
});
|
||||
this.$videoToggle.on('click', function () {
|
||||
Handlers.videoToggleClick.call(self);
|
||||
});
|
||||
this.$cursorToggle.on('click', function () {
|
||||
Handlers.cursorToggleClick.call(self);
|
||||
});
|
||||
this.$soundToggle.on('click', function () {
|
||||
Handlers.soundToggleClick.call(self);
|
||||
});
|
||||
this.$messageInput.on('keyup', function (event) {
|
||||
Handlers.keyUp.call(self, event);
|
||||
});
|
||||
this.$messageInput.on('focus', function () {
|
||||
Handlers.inputFocus.call(self);
|
||||
});
|
||||
this.$messageInput.on('blur', function () {
|
||||
Handlers.inputBlur.call(self);
|
||||
});
|
||||
},
|
||||
initializeSounds: function() {
|
||||
this.sound = new Howl({
|
||||
urls: ["<%= asset_path 'sounds/MM_sounds.mp3' %>", "<%= asset_path 'sounds/MM_sounds.ogg' %>"],
|
||||
sprite: {
|
||||
joinmap: [0, 561],
|
||||
leavemap: [1000, 592],
|
||||
receivechat: [2000, 318],
|
||||
sendchat: [3000, 296],
|
||||
sessioninvite: [4000, 5393, true]
|
||||
}
|
||||
});
|
||||
},
|
||||
incrementUnread: function() {
|
||||
this.unreadMessages++;
|
||||
this.$unread.html(this.unreadMessages);
|
||||
this.$unread.show();
|
||||
},
|
||||
addMessage: function(message, isInitial, wasMe) {
|
||||
|
||||
if (!this.isOpen && !isInitial) Private.incrementUnread.call(this);
|
||||
|
||||
function addZero(i) {
|
||||
if (i < 10) {
|
||||
i = "0" + i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
var m = _.clone(message.attributes);
|
||||
|
||||
var today = new Date();
|
||||
m.timestamp = new Date(m.created_at);
|
||||
|
||||
var date = (m.timestamp.getMonth() + 1) + '/' + m.timestamp.getDate();
|
||||
date += " " + addZero(m.timestamp.getHours()) + ":" + addZero(m.timestamp.getMinutes());
|
||||
m.timestamp = date;
|
||||
m.image = m.user_image || 'http://www.hotpepper.ca/wp-content/uploads/2014/11/default_profile_1_200x200.png'; // TODO: remove
|
||||
m.message = linker.link(m.message);
|
||||
var $html = $(this.messageTemplate(m));
|
||||
this.$messages.append($html);
|
||||
if (!isInitial) this.scrollMessages(200);
|
||||
|
||||
if (!wasMe && !isInitial && this.alertSound) this.sound.play('receivechat');
|
||||
},
|
||||
initialMessages: function() {
|
||||
var messages = this.messages.models;
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
Private.addMessage.call(this, messages[i], true);
|
||||
}
|
||||
},
|
||||
handleInputMessage: function() {
|
||||
var message = {
|
||||
message: this.$messageInput.val(),
|
||||
};
|
||||
this.$messageInput.val('');
|
||||
$(document).trigger(chatView.events.message + '-' + this.room, [message]);
|
||||
},
|
||||
addParticipant: function(participant) {
|
||||
var p = _.clone(participant.attributes);
|
||||
if (p.self) {
|
||||
p.selfClass = 'is-self';
|
||||
p.selfName = '(me)';
|
||||
} else {
|
||||
p.selfClass = '';
|
||||
p.selfName = '';
|
||||
}
|
||||
var html = this.participantTemplate(p);
|
||||
this.$participants.append(html);
|
||||
},
|
||||
removeParticipant: function(participant) {
|
||||
this.$container.find('.participant-' + participant.get('id')).remove();
|
||||
}
|
||||
};
|
||||
|
||||
var Handlers = {
|
||||
buttonClick: function() {
|
||||
if (this.isOpen) this.close();
|
||||
else if (!this.isOpen) this.open();
|
||||
},
|
||||
videoToggleClick: function() {
|
||||
this.$videoToggle.toggleClass('active');
|
||||
this.videosShowing = !this.videosShowing;
|
||||
$(document).trigger(this.videosShowing ? chatView.events.videosOn : chatView.events.videosOff);
|
||||
},
|
||||
cursorToggleClick: function() {
|
||||
this.$cursorToggle.toggleClass('active');
|
||||
this.cursorsShowing = !this.cursorsShowing;
|
||||
$(document).trigger(this.cursorsShowing ? chatView.events.cursorsOn : chatView.events.cursorsOff);
|
||||
},
|
||||
soundToggleClick: function() {
|
||||
this.alertSound = !this.alertSound;
|
||||
this.$soundToggle.toggleClass('active');
|
||||
},
|
||||
keyUp: function(event) {
|
||||
switch(event.which) {
|
||||
case 13: // enter
|
||||
Private.handleInputMessage.call(this);
|
||||
break;
|
||||
}
|
||||
},
|
||||
inputFocus: function() {
|
||||
$(document).trigger(chatView.events.inputFocus);
|
||||
},
|
||||
inputBlur: function() {
|
||||
$(document).trigger(chatView.events.inputBlur);
|
||||
}
|
||||
};
|
||||
|
||||
chatView = function(messages, mapper, room) {
|
||||
var self = this;
|
||||
|
||||
this.room = room;
|
||||
this.mapper = mapper;
|
||||
this.messages = messages; // backbone collection
|
||||
|
||||
this.isOpen = false;
|
||||
this.alertSound = true; // whether to play sounds on arrival of new messages or not
|
||||
this.cursorsShowing = true;
|
||||
this.videosShowing = true;
|
||||
this.unreadMessages = 0;
|
||||
this.participants = new Backbone.Collection();
|
||||
|
||||
Private.templates.call(this);
|
||||
Private.createElements.call(this);
|
||||
Private.attachElements.call(this);
|
||||
Private.addEventListeners.call(this);
|
||||
Private.initialMessages.call(this);
|
||||
Private.initializeSounds.call(this);
|
||||
this.$container.css({
|
||||
right: '-300px'
|
||||
});
|
||||
};
|
||||
|
||||
chatView.prototype.conversationInProgress = function (participating) {
|
||||
this.$conversationInProgress.show();
|
||||
this.$participants.addClass('is-live');
|
||||
if (participating) this.$participants.addClass('is-participating');
|
||||
this.$button.addClass('active');
|
||||
|
||||
// hide invite to call buttons
|
||||
}
|
||||
|
||||
chatView.prototype.conversationEnded = function () {
|
||||
this.$conversationInProgress.hide();
|
||||
this.$participants.removeClass('is-live');
|
||||
this.$participants.removeClass('is-participating');
|
||||
this.$button.removeClass('active');
|
||||
this.$participants.find('.participant').removeClass('active');
|
||||
this.$participants.find('.participant').removeClass('pending');
|
||||
}
|
||||
|
||||
chatView.prototype.leaveConversation = function () {
|
||||
this.$participants.removeClass('is-participating');
|
||||
}
|
||||
|
||||
chatView.prototype.mapperJoinedCall = function (id) {
|
||||
this.$participants.find('.participant-' + id).addClass('active');
|
||||
}
|
||||
|
||||
chatView.prototype.mapperLeftCall = function (id) {
|
||||
this.$participants.find('.participant-' + id).removeClass('active');
|
||||
}
|
||||
|
||||
chatView.prototype.invitationPending = function (id) {
|
||||
this.$participants.find('.participant-' + id).addClass('pending');
|
||||
}
|
||||
|
||||
chatView.prototype.invitationAnswered = function (id) {
|
||||
this.$participants.find('.participant-' + id).removeClass('pending');
|
||||
}
|
||||
|
||||
chatView.prototype.addParticipant = function (participant) {
|
||||
this.participants.add(participant);
|
||||
}
|
||||
|
||||
chatView.prototype.removeParticipant = function (username) {
|
||||
var p = this.participants.find(function (p) { return p.get('username') === username; });
|
||||
if (p) {
|
||||
this.participants.remove(p);
|
||||
}
|
||||
}
|
||||
|
||||
chatView.prototype.removeParticipants = function () {
|
||||
this.participants.remove(this.participants.models);
|
||||
}
|
||||
|
||||
chatView.prototype.open = function () {
|
||||
this.$container.css({
|
||||
right: '0'
|
||||
});
|
||||
this.$messageInput.focus();
|
||||
this.isOpen = true;
|
||||
this.unreadMessages = 0;
|
||||
this.$unread.hide();
|
||||
this.scrollMessages(0);
|
||||
$(document).trigger(chatView.events.openTray);
|
||||
}
|
||||
|
||||
chatView.prototype.addMessage = function(message, isInitial, wasMe) {
|
||||
this.messages.add(message);
|
||||
Private.addMessage.call(this, message, isInitial, wasMe);
|
||||
}
|
||||
|
||||
chatView.prototype.scrollMessages = function(duration) {
|
||||
duration = duration || 0;
|
||||
|
||||
this.$messages.animate({
|
||||
scrollTop: this.$messages[0].scrollHeight
|
||||
}, duration);
|
||||
}
|
||||
|
||||
chatView.prototype.clearMessages = function () {
|
||||
this.unreadMessages = 0;
|
||||
this.$unread.hide();
|
||||
this.$messages.empty();
|
||||
}
|
||||
|
||||
chatView.prototype.close = function () {
|
||||
this.$container.css({
|
||||
right: '-300px'
|
||||
});
|
||||
this.$messageInput.blur();
|
||||
this.isOpen = false;
|
||||
$(document).trigger(chatView.events.closeTray);
|
||||
}
|
||||
|
||||
chatView.prototype.remove = function () {
|
||||
this.$button.off();
|
||||
this.$container.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @static
|
||||
*/
|
||||
chatView.events = {
|
||||
message: 'ChatView:message',
|
||||
openTray: 'ChatView:openTray',
|
||||
closeTray: 'ChatView:closeTray',
|
||||
inputFocus: 'ChatView:inputFocus',
|
||||
inputBlur: 'ChatView:inputBlur',
|
||||
cursorsOff: 'ChatView:cursorsOff',
|
||||
cursorsOn: 'ChatView:cursorsOn',
|
||||
videosOff: 'ChatView:videosOff',
|
||||
videosOn: 'ChatView:videosOn'
|
||||
};
|
||||
|
||||
return chatView;
|
||||
|
||||
})();
|
|
@ -1,195 +0,0 @@
|
|||
Metamaps.Views = Metamaps.Views || {};
|
||||
|
||||
Metamaps.Views.room = (function () {
|
||||
|
||||
var ChatView = Metamaps.Views.chatView;
|
||||
var VideoView = Metamaps.Views.videoView;
|
||||
|
||||
var room = function(opts) {
|
||||
var self = this;
|
||||
|
||||
this.isActiveRoom = false;
|
||||
this.socket = opts.socket;
|
||||
this.webrtc = opts.webrtc;
|
||||
//this.roomRef = opts.firebase;
|
||||
this.room = opts.room;
|
||||
this.config = opts.config;
|
||||
this.peopleCount = 0;
|
||||
|
||||
this.$myVideo = opts.$video;
|
||||
this.myVideo = opts.myVideoView;
|
||||
|
||||
this.messages = new Backbone.Collection();
|
||||
this.currentMapper = new Backbone.Model({ name: opts.username, image: opts.image });
|
||||
this.chat = new ChatView(this.messages, this.currentMapper, this.room);
|
||||
|
||||
this.videos = {};
|
||||
|
||||
this.init();
|
||||
};
|
||||
|
||||
room.prototype.join = function(cb) {
|
||||
this.isActiveRoom = true;
|
||||
this.webrtc.joinRoom(this.room, cb);
|
||||
this.chat.conversationInProgress(true); // true indicates participation
|
||||
}
|
||||
|
||||
room.prototype.conversationInProgress = function() {
|
||||
this.chat.conversationInProgress(false); // false indicates not participating
|
||||
}
|
||||
|
||||
room.prototype.conversationEnding = function() {
|
||||
this.chat.conversationEnded();
|
||||
}
|
||||
|
||||
room.prototype.leaveVideoOnly = function() {
|
||||
this.chat.leaveConversation(); // the conversation will carry on without you
|
||||
for (var id in this.videos) {
|
||||
this.removeVideo(id);
|
||||
}
|
||||
this.isActiveRoom = false;
|
||||
this.webrtc.leaveRoom();
|
||||
}
|
||||
|
||||
room.prototype.leave = function() {
|
||||
for (var id in this.videos) {
|
||||
this.removeVideo(id);
|
||||
}
|
||||
this.isActiveRoom = false;
|
||||
this.webrtc.leaveRoom();
|
||||
this.chat.conversationEnded();
|
||||
this.chat.removeParticipants();
|
||||
this.chat.clearMessages();
|
||||
this.messages.reset();
|
||||
}
|
||||
|
||||
room.prototype.setPeopleCount = function(count) {
|
||||
this.peopleCount = count;
|
||||
}
|
||||
|
||||
room.prototype.init = function () {
|
||||
var self = this;
|
||||
|
||||
$(document).on(VideoView.events.audioControlClick, function (event, videoView) {
|
||||
if (!videoView.audioStatus) self.webrtc.mute();
|
||||
else if (videoView.audioStatus) self.webrtc.unmute();
|
||||
});
|
||||
$(document).on(VideoView.events.videoControlClick, function (event, videoView) {
|
||||
if (!videoView.videoStatus) self.webrtc.pauseVideo();
|
||||
else if (videoView.videoStatus) self.webrtc.resumeVideo();
|
||||
});
|
||||
|
||||
this.webrtc.webrtc.off('peerStreamAdded');
|
||||
this.webrtc.webrtc.off('peerStreamRemoved');
|
||||
this.webrtc.on('peerStreamAdded', function (peer) {
|
||||
var mapper = Metamaps.Realtime.mappersOnMap[peer.nick];
|
||||
peer.avatar = mapper.image;
|
||||
peer.username = mapper.name;
|
||||
if (self.isActiveRoom) {
|
||||
self.addVideo(peer);
|
||||
}
|
||||
});
|
||||
|
||||
this.webrtc.on('peerStreamRemoved', function (peer) {
|
||||
if (self.isActiveRoom) {
|
||||
self.removeVideo(peer);
|
||||
}
|
||||
});
|
||||
|
||||
this.webrtc.on('mute', function (data) {
|
||||
var v = self.videos[data.id];
|
||||
if (!v) return;
|
||||
|
||||
if (data.name === 'audio') {
|
||||
v.audioStatus = false;
|
||||
}
|
||||
else if (data.name === 'video') {
|
||||
v.videoStatus = false;
|
||||
v.$avatar.show();
|
||||
}
|
||||
if (!v.audioStatus && !v.videoStatus) v.$container.hide();
|
||||
});
|
||||
this.webrtc.on('unmute', function (data) {
|
||||
var v = self.videos[data.id];
|
||||
if (!v) return;
|
||||
|
||||
if (data.name === 'audio') {
|
||||
v.audioStatus = true;
|
||||
}
|
||||
else if (data.name === 'video') {
|
||||
v.videoStatus = true;
|
||||
v.$avatar.hide();
|
||||
}
|
||||
v.$container.show();
|
||||
});
|
||||
|
||||
var sendChatMessage = function (event, data) {
|
||||
self.sendChatMessage(data);
|
||||
};
|
||||
$(document).on(ChatView.events.message + '-' + this.room, sendChatMessage);
|
||||
}
|
||||
|
||||
room.prototype.videoAdded = function (callback) {
|
||||
this._videoAdded = callback;
|
||||
}
|
||||
|
||||
room.prototype.addVideo = function (peer) {
|
||||
var
|
||||
id = this.webrtc.getDomId(peer),
|
||||
video = attachMediaStream(peer.stream);
|
||||
|
||||
var
|
||||
v = new VideoView(video, null, id, false, { DOUBLE_CLICK_TOLERANCE: 200, avatar: peer.avatar, username: peer.username });
|
||||
|
||||
this.videos[peer.id] = v;
|
||||
if (this._videoAdded) this._videoAdded(v, peer.nick);
|
||||
}
|
||||
|
||||
room.prototype.removeVideo = function (peer) {
|
||||
var id = typeof peer == 'string' ? peer : peer.id;
|
||||
if (this.videos[id]) {
|
||||
this.videos[id].remove();
|
||||
delete this.videos[id];
|
||||
}
|
||||
}
|
||||
|
||||
room.prototype.sendChatMessage = function (data) {
|
||||
var self = this;
|
||||
//this.roomRef.child('messages').push(data);
|
||||
if (self.chat.alertSound) self.chat.sound.play('sendchat');
|
||||
var m = new Metamaps.Backbone.Message({
|
||||
message: data.message,
|
||||
resource_id: Metamaps.Active.Map.id,
|
||||
resource_type: "Map"
|
||||
});
|
||||
m.save(null, {
|
||||
success: function (model, response) {
|
||||
self.addMessages(new Metamaps.Backbone.MessageCollection(model), false, true);
|
||||
$(document).trigger(room.events.newMessage, [model]);
|
||||
},
|
||||
error: function (model, response) {
|
||||
console.log('error!', response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// they should be instantiated as backbone models before they get
|
||||
// passed to this function
|
||||
room.prototype.addMessages = function (messages, isInitial, wasMe) {
|
||||
var self = this;
|
||||
|
||||
messages.models.forEach(function (message) {
|
||||
self.chat.addMessage(message, isInitial, wasMe);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @static
|
||||
*/
|
||||
room.events = {
|
||||
newMessage: "Room:newMessage"
|
||||
};
|
||||
|
||||
return room;
|
||||
})();
|
|
@ -1,207 +0,0 @@
|
|||
Metamaps.Views = Metamaps.Views || {};
|
||||
|
||||
Metamaps.Views.videoView = (function () {
|
||||
|
||||
var videoView;
|
||||
|
||||
var Private = {
|
||||
addControls: function() {
|
||||
var self = this;
|
||||
|
||||
this.$audioControl = $('<div class="video-audio"></div>');
|
||||
this.$videoControl = $('<div class="video-video"></div>');
|
||||
|
||||
this.$audioControl.on('click', function () {
|
||||
Handlers.audioControlClick.call(self);
|
||||
});
|
||||
|
||||
this.$videoControl.on('click', function () {
|
||||
Handlers.videoControlClick.call(self);
|
||||
});
|
||||
|
||||
this.$container.append(this.$audioControl);
|
||||
this.$container.append(this.$videoControl);
|
||||
},
|
||||
cancelClick: function() {
|
||||
this.mouseIsDown = false;
|
||||
|
||||
if (this.hasMoved) {
|
||||
|
||||
}
|
||||
|
||||
$(document).trigger(videoView.events.dragEnd);
|
||||
}
|
||||
};
|
||||
|
||||
var Handlers = {
|
||||
mousedown: function(event) {
|
||||
this.mouseIsDown = true;
|
||||
this.hasMoved = false;
|
||||
this.mouseMoveStart = {
|
||||
x: event.pageX,
|
||||
y: event.pageY
|
||||
};
|
||||
this.posStart = {
|
||||
x: parseInt(this.$container.css('left'), '10'),
|
||||
y: parseInt(this.$container.css('top'), '10')
|
||||
}
|
||||
|
||||
$(document).trigger(videoView.events.mousedown);
|
||||
},
|
||||
mouseup: function(event) {
|
||||
$(document).trigger(videoView.events.mouseup, [this]);
|
||||
|
||||
var storedTime = this.lastClick;
|
||||
var now = Date.now();
|
||||
this.lastClick = now;
|
||||
|
||||
if (now - storedTime < this.config.DOUBLE_CLICK_TOLERANCE) {
|
||||
$(document).trigger(videoView.events.doubleClick, [this]);
|
||||
}
|
||||
},
|
||||
mousemove: function(event) {
|
||||
var
|
||||
diffX,
|
||||
diffY,
|
||||
newX,
|
||||
newY;
|
||||
|
||||
if (this.$parent && this.mouseIsDown) {
|
||||
this.manuallyPositioned = true;
|
||||
this.hasMoved = true;
|
||||
diffX = event.pageX - this.mouseMoveStart.x;
|
||||
diffY = this.mouseMoveStart.y - event.pageY;
|
||||
newX = this.posStart.x + diffX;
|
||||
newY = this.posStart.y - diffY;
|
||||
this.$container.css({
|
||||
top: newY,
|
||||
left: newX
|
||||
});
|
||||
}
|
||||
},
|
||||
audioControlClick: function() {
|
||||
if (this.audioStatus) {
|
||||
this.audioOff();
|
||||
} else {
|
||||
this.audioOn();
|
||||
}
|
||||
$(document).trigger(videoView.events.audioControlClick, [this]);
|
||||
},
|
||||
videoControlClick: function() {
|
||||
if (this.videoStatus) {
|
||||
this.videoOff();
|
||||
} else {
|
||||
this.videoOn();
|
||||
}
|
||||
$(document).trigger(videoView.events.videoControlClick, [this]);
|
||||
},
|
||||
};
|
||||
|
||||
var videoView = function(video, $parent, id, isMyself, config) {
|
||||
var self = this;
|
||||
|
||||
this.$parent = $parent; // mapView
|
||||
|
||||
this.video = video;
|
||||
this.id = id;
|
||||
|
||||
this.config = config;
|
||||
|
||||
this.mouseIsDown = false;
|
||||
this.mouseDownOffset = { x: 0, y: 0 };
|
||||
this.lastClick = null;
|
||||
this.hasMoved = false;
|
||||
|
||||
this.audioStatus = true;
|
||||
this.videoStatus = true;
|
||||
|
||||
this.$container = $('<div></div>');
|
||||
this.$container.addClass('collaborator-video' + (isMyself ? ' my-video' : ''));
|
||||
this.$container.attr('id', 'container_' + id);
|
||||
|
||||
|
||||
var $vidContainer = $('<div></div>');
|
||||
$vidContainer.addClass('video-cutoff');
|
||||
$vidContainer.append(this.video);
|
||||
|
||||
this.avatar = config.avatar;
|
||||
this.$avatar = $('<img draggable="false" class="collaborator-video-avatar" src="' + config.avatar + '" width="150" height="150" />');
|
||||
$vidContainer.append(this.$avatar);
|
||||
|
||||
this.$container.append($vidContainer);
|
||||
|
||||
this.$container.on('mousedown', function (event) {
|
||||
Handlers.mousedown.call(self, event);
|
||||
});
|
||||
|
||||
if (isMyself) {
|
||||
Private.addControls.call(this);
|
||||
}
|
||||
|
||||
// suppress contextmenu
|
||||
this.video.oncontextmenu = function () { return false; };
|
||||
|
||||
if (this.$parent) this.setParent(this.$parent);
|
||||
};
|
||||
|
||||
videoView.prototype.setParent = function($parent) {
|
||||
var self = this;
|
||||
this.$parent = $parent;
|
||||
this.$parent.off('.video' + this.id);
|
||||
this.$parent.on('mouseup.video' + this.id, function (event) {
|
||||
Handlers.mouseup.call(self, event);
|
||||
Private.cancelClick.call(self);
|
||||
});
|
||||
this.$parent.on('mousemove.video' + this.id, function (event) {
|
||||
Handlers.mousemove.call(self, event);
|
||||
});
|
||||
}
|
||||
|
||||
videoView.prototype.setAvatar = function (src) {
|
||||
this.$avatar.attr('src', src);
|
||||
this.avatar = src;
|
||||
}
|
||||
|
||||
videoView.prototype.remove = function () {
|
||||
this.$container.off();
|
||||
if (this.$parent) this.$parent.off('.video' + this.id);
|
||||
this.$container.remove();
|
||||
}
|
||||
|
||||
videoView.prototype.videoOff = function () {
|
||||
this.$videoControl.addClass('active');
|
||||
this.$avatar.show();
|
||||
this.videoStatus = false;
|
||||
}
|
||||
|
||||
videoView.prototype.videoOn = function () {
|
||||
this.$videoControl.removeClass('active');
|
||||
this.$avatar.hide();
|
||||
this.videoStatus = true;
|
||||
}
|
||||
|
||||
videoView.prototype.audioOff = function () {
|
||||
this.$audioControl.addClass('active');
|
||||
this.audioStatus = false;
|
||||
}
|
||||
|
||||
videoView.prototype.audioOn = function () {
|
||||
this.$audioControl.removeClass('active');
|
||||
this.audioStatus = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @static
|
||||
*/
|
||||
videoView.events = {
|
||||
mousedown: "VideoView:mousedown",
|
||||
mouseup: "VideoView:mouseup",
|
||||
doubleClick: "VideoView:doubleClick",
|
||||
dragEnd: "VideoView:dragEnd",
|
||||
audioControlClick: "VideoView:audioControlClick",
|
||||
videoControlClick: "VideoView:videoControlClick",
|
||||
};
|
||||
|
||||
return videoView;
|
||||
})();
|
|
@ -87,8 +87,6 @@ server to see what problems show up:
|
|||
sudo npm install -g forever
|
||||
(crontab -u metamaps -l 2>/dev/null; echo "@reboot $(which forever) --append -l /home/metamaps/logs/forever.realtime.log start /home/metamaps/metamaps/realtime/realtime-server.js") | crontab -u metamaps -
|
||||
|
||||
cd /home/metamaps/metamaps/realtime
|
||||
npm install
|
||||
mkdir -p /home/metamaps/logs
|
||||
forever --append -l /home/metamaps/logs/forever.realtime.log \
|
||||
start /home/metamaps/metamaps/realtime/realtime-server.js
|
||||
|
|
|
@ -29,9 +29,7 @@ Now that you have the code, run these commands:
|
|||
rake perms:fix
|
||||
passenger-config restart-app .
|
||||
|
||||
cd realtime
|
||||
npm install
|
||||
forever list #find the uid, e.g. xQKv
|
||||
forever list #find the uid of the realtime server, e.g. xQKv
|
||||
forever restart xQKv
|
||||
|
||||
sudo service metamaps_delayed_job restart
|
||||
|
|
|
@ -1,42 +1,34 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Account.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Erb
|
||||
/*
|
||||
* Metamaps.Erb
|
||||
*/
|
||||
|
||||
Metamaps.Account = {
|
||||
const Account = {
|
||||
listenersInitialized: false,
|
||||
init: function () {
|
||||
var self = Metamaps.Account
|
||||
},
|
||||
initListeners: function () {
|
||||
var self = Metamaps.Account
|
||||
var self = Account
|
||||
|
||||
$('#user_image').change(self.showImagePreview)
|
||||
self.listenersInitialized = true
|
||||
},
|
||||
toggleChangePicture: function () {
|
||||
var self = Metamaps.Account
|
||||
var self = Account
|
||||
|
||||
$('.userImageMenu').toggle()
|
||||
if (!self.listenersInitialized) self.initListeners()
|
||||
},
|
||||
openChangePicture: function () {
|
||||
var self = Metamaps.Account
|
||||
var self = Account
|
||||
|
||||
$('.userImageMenu').show()
|
||||
if (!self.listenersInitialized) self.initListeners()
|
||||
},
|
||||
closeChangePicture: function () {
|
||||
var self = Metamaps.Account
|
||||
var self = Account
|
||||
|
||||
$('.userImageMenu').hide()
|
||||
},
|
||||
showLoading: function () {
|
||||
var self = Metamaps.Account
|
||||
var self = Account
|
||||
|
||||
var loader = new CanvasLoader('accountPageLoading')
|
||||
loader.setColor('#4FC059'); // default is '#000000'
|
||||
|
@ -47,7 +39,7 @@ Metamaps.Account = {
|
|||
$('#accountPageLoading').show()
|
||||
},
|
||||
showImagePreview: function () {
|
||||
var self = Metamaps.Account
|
||||
var self = Account
|
||||
|
||||
var file = $('#user_image')[0].files[0]
|
||||
|
||||
|
@ -93,10 +85,10 @@ Metamaps.Account = {
|
|||
}
|
||||
},
|
||||
removePicture: function () {
|
||||
var self = Metamaps.Account
|
||||
var self = Account
|
||||
|
||||
$('.userImageDiv canvas').remove()
|
||||
$('.userImageDiv img').attr('src', Metamaps.Erb['user.png']).show()
|
||||
$('.userImageDiv img').attr('src', window.Metamaps.Erb['user.png']).show()
|
||||
$('.userImageMenu').hide()
|
||||
|
||||
var input = $('#user_image')
|
||||
|
@ -120,3 +112,5 @@ Metamaps.Account = {
|
|||
$('#user_password_confirmation').val('')
|
||||
}
|
||||
}
|
||||
|
||||
export default Account
|
7
frontend/src/Metamaps/Active.js
Normal file
7
frontend/src/Metamaps/Active.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const Active = {
|
||||
Map: null,
|
||||
Topic: null,
|
||||
Mapper: null
|
||||
};
|
||||
|
||||
export default Active
|
|
@ -1,35 +1,29 @@
|
|||
/* global Metamaps, $ */
|
||||
/* global $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Admin.js.erb
|
||||
*
|
||||
* Dependencies: none!
|
||||
*/
|
||||
|
||||
Metamaps.Admin = {
|
||||
const Admin = {
|
||||
selectMetacodes: [],
|
||||
allMetacodes: [],
|
||||
init: function () {
|
||||
var self = Metamaps.Admin
|
||||
var self = Admin
|
||||
|
||||
$('#metacodes_value').val(self.selectMetacodes.toString())
|
||||
},
|
||||
selectAll: function () {
|
||||
var self = Metamaps.Admin
|
||||
var self = Admin
|
||||
|
||||
$('.editMetacodes li').removeClass('toggledOff')
|
||||
self.selectMetacodes = self.allMetacodes.slice(0)
|
||||
$('#metacodes_value').val(self.selectMetacodes.toString())
|
||||
},
|
||||
deselectAll: function () {
|
||||
var self = Metamaps.Admin
|
||||
var self = Admin
|
||||
|
||||
$('.editMetacodes li').addClass('toggledOff')
|
||||
self.selectMetacodes = []
|
||||
$('#metacodes_value').val(0)
|
||||
},
|
||||
liClickHandler: function () {
|
||||
var self = Metamaps.Admin
|
||||
var self = Admin
|
||||
|
||||
if ($(this).attr('class') != 'toggledOff') {
|
||||
$(this).addClass('toggledOff')
|
||||
|
@ -44,7 +38,7 @@ Metamaps.Admin = {
|
|||
}
|
||||
},
|
||||
validate: function () {
|
||||
var self = Metamaps.Admin
|
||||
var self = Admin
|
||||
|
||||
if (self.selectMetacodes.length == 0) {
|
||||
alert('Would you pretty please select at least one metacode for the set?')
|
||||
|
@ -52,3 +46,5 @@ Metamaps.Admin = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Admin
|
|
@ -1,12 +1,4 @@
|
|||
/* global Metamaps */
|
||||
|
||||
/*
|
||||
* Metmaaps.AutoLayout.js
|
||||
*
|
||||
* Dependencies: none!
|
||||
*/
|
||||
|
||||
Metamaps.AutoLayout = {
|
||||
const AutoLayout = {
|
||||
nextX: 0,
|
||||
nextY: 0,
|
||||
sideLength: 1,
|
||||
|
@ -16,7 +8,7 @@ Metamaps.AutoLayout = {
|
|||
timeToTurn: 0,
|
||||
|
||||
getNextCoord: function () {
|
||||
var self = Metamaps.AutoLayout
|
||||
var self = AutoLayout
|
||||
var nextX = self.nextX
|
||||
var nextY = self.nextY
|
||||
|
||||
|
@ -63,7 +55,7 @@ Metamaps.AutoLayout = {
|
|||
}
|
||||
},
|
||||
resetSpiral: function () {
|
||||
var self = Metamaps.AutoLayout
|
||||
var self = AutoLayout
|
||||
self.nextX = 0
|
||||
self.nextY = 0
|
||||
self.nextXshift = 1
|
||||
|
@ -73,3 +65,5 @@ Metamaps.AutoLayout = {
|
|||
self.turnCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
export default AutoLayout
|
|
@ -1,33 +1,38 @@
|
|||
/* global Metamaps, Backbone, _, $ */
|
||||
/* global Metamaps, Backbone, $ */
|
||||
|
||||
import _ from 'lodash'
|
||||
import Backbone from 'backbone'
|
||||
Backbone.$ = window.$
|
||||
|
||||
import Active from '../Active'
|
||||
import Filter from '../Filter'
|
||||
import JIT from '../JIT'
|
||||
import Map, { InfoBox } from '../Map'
|
||||
import Mapper from '../Mapper'
|
||||
import Realtime from '../Realtime'
|
||||
import Synapse from '../Synapse'
|
||||
import SynapseCard from '../SynapseCard'
|
||||
import Topic from '../Topic'
|
||||
import TopicCard from '../TopicCard'
|
||||
import Visualize from '../Visualize'
|
||||
|
||||
/*
|
||||
* Metamaps.Backbone.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.Collaborators
|
||||
* - Metamaps.Creators
|
||||
* - Metamaps.Filter
|
||||
* - Metamaps.JIT
|
||||
* - Metamaps.Loading
|
||||
* - Metamaps.Map
|
||||
* - Metamaps.Mapper
|
||||
* - Metamaps.Mappers
|
||||
* - Metamaps.Mappings
|
||||
* - Metamaps.Metacodes
|
||||
* - Metamaps.Realtime
|
||||
* - Metamaps.Synapse
|
||||
* - Metamaps.SynapseCard
|
||||
* - Metamaps.Synapses
|
||||
* - Metamaps.Topic
|
||||
* - Metamaps.TopicCard
|
||||
* - Metamaps.Topics
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
|
||||
Metamaps.Backbone = {}
|
||||
const _Backbone = {}
|
||||
|
||||
Metamaps.Backbone.Map = Backbone.Model.extend({
|
||||
_Backbone.Map = Backbone.Model.extend({
|
||||
urlRoot: '/maps',
|
||||
blacklist: ['created_at', 'updated_at', 'created_at_clean', 'updated_at_clean', 'user_name', 'contributor_count', 'topic_count', 'synapse_count', 'topics', 'synapses', 'mappings', 'mappers'],
|
||||
toJSON: function (options) {
|
||||
|
@ -58,7 +63,7 @@ Metamaps.Backbone.Map = Backbone.Model.extend({
|
|||
this.on('saved', this.savedEvent)
|
||||
},
|
||||
savedEvent: function () {
|
||||
Metamaps.Realtime.sendMapChange(this)
|
||||
Realtime.sendMapChange(this)
|
||||
},
|
||||
authorizeToEdit: function (mapper) {
|
||||
if (mapper && (
|
||||
|
@ -78,10 +83,10 @@ Metamaps.Backbone.Map = Backbone.Model.extend({
|
|||
}
|
||||
},
|
||||
getUser: function () {
|
||||
return Metamaps.Mapper.get(this.get('user_id'))
|
||||
return Mapper.get(this.get('user_id'))
|
||||
},
|
||||
fetchContained: function () {
|
||||
var bb = Metamaps.Backbone
|
||||
var bb = _Backbone
|
||||
var that = this
|
||||
var start = function (data) {
|
||||
that.set('mappers', new bb.MapperCollection(data.mappers))
|
||||
|
@ -122,10 +127,10 @@ Metamaps.Backbone.Map = Backbone.Model.extend({
|
|||
return this.get('mappers')
|
||||
},
|
||||
updateView: function () {
|
||||
var map = Metamaps.Active.Map
|
||||
var map = Active.Map
|
||||
var isActiveMap = this.id === map.id
|
||||
if (isActiveMap) {
|
||||
Metamaps.Map.InfoBox.updateNameDescPerm(this.get('name'), this.get('desc'), this.get('permission'))
|
||||
InfoBox.updateNameDescPerm(this.get('name'), this.get('desc'), this.get('permission'))
|
||||
this.updateMapWrapper()
|
||||
// mobile menu
|
||||
$('#header_content').html(this.get('name'))
|
||||
|
@ -133,17 +138,17 @@ Metamaps.Backbone.Map = Backbone.Model.extend({
|
|||
}
|
||||
},
|
||||
updateMapWrapper: function () {
|
||||
var map = Metamaps.Active.Map
|
||||
var map = Active.Map
|
||||
var isActiveMap = this.id === map.id
|
||||
var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : ''
|
||||
var authorized = map && map.authorizeToEdit(Active.Mapper) ? 'canEditMap' : ''
|
||||
var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : ''
|
||||
if (isActiveMap) {
|
||||
$('.wrapper').removeClass('canEditMap commonsMap').addClass(authorized + ' ' + commonsMap)
|
||||
}
|
||||
}
|
||||
})
|
||||
Metamaps.Backbone.MapsCollection = Backbone.Collection.extend({
|
||||
model: Metamaps.Backbone.Map,
|
||||
_Backbone.MapsCollection = Backbone.Collection.extend({
|
||||
model: _Backbone.Map,
|
||||
initialize: function (models, options) {
|
||||
this.id = options.id
|
||||
this.sortBy = options.sortBy
|
||||
|
@ -210,7 +215,7 @@ Metamaps.Backbone.MapsCollection = Backbone.Collection.extend({
|
|||
}
|
||||
})
|
||||
|
||||
Metamaps.Backbone.Message = Backbone.Model.extend({
|
||||
_Backbone.Message = Backbone.Model.extend({
|
||||
urlRoot: '/messages',
|
||||
blacklist: ['created_at', 'updated_at'],
|
||||
toJSON: function (options) {
|
||||
|
@ -226,12 +231,12 @@ Metamaps.Backbone.Message = Backbone.Model.extend({
|
|||
*/
|
||||
}
|
||||
})
|
||||
Metamaps.Backbone.MessageCollection = Backbone.Collection.extend({
|
||||
model: Metamaps.Backbone.Message,
|
||||
_Backbone.MessageCollection = Backbone.Collection.extend({
|
||||
model: _Backbone.Message,
|
||||
url: '/messages'
|
||||
})
|
||||
|
||||
Metamaps.Backbone.Mapper = Backbone.Model.extend({
|
||||
_Backbone.Mapper = Backbone.Model.extend({
|
||||
urlRoot: '/users',
|
||||
blacklist: ['created_at', 'updated_at'],
|
||||
toJSON: function (options) {
|
||||
|
@ -247,13 +252,13 @@ Metamaps.Backbone.Mapper = Backbone.Model.extend({
|
|||
}
|
||||
})
|
||||
|
||||
Metamaps.Backbone.MapperCollection = Backbone.Collection.extend({
|
||||
model: Metamaps.Backbone.Mapper,
|
||||
_Backbone.MapperCollection = Backbone.Collection.extend({
|
||||
model: _Backbone.Mapper,
|
||||
url: '/users'
|
||||
})
|
||||
|
||||
Metamaps.Backbone.init = function () {
|
||||
var self = Metamaps.Backbone
|
||||
_Backbone.init = function () {
|
||||
var self = _Backbone
|
||||
|
||||
self.Metacode = Backbone.Model.extend({
|
||||
initialize: function () {
|
||||
|
@ -320,10 +325,10 @@ Metamaps.Backbone.init = function () {
|
|||
initialize: function () {
|
||||
if (this.isNew()) {
|
||||
this.set({
|
||||
'user_id': Metamaps.Active.Mapper.id,
|
||||
'user_id': Active.Mapper.id,
|
||||
'desc': this.get('desc') || '',
|
||||
'link': this.get('link') || '',
|
||||
'permission': Metamaps.Active.Map ? Metamaps.Active.Map.get('permission') : 'commons'
|
||||
'permission': Active.Map ? Active.Map.get('permission') : 'commons'
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -335,7 +340,7 @@ Metamaps.Backbone.init = function () {
|
|||
mappableid: this.id
|
||||
}
|
||||
|
||||
$(document).trigger(Metamaps.JIT.events.removeTopic, [removeTopicData])
|
||||
$(document).trigger(JIT.events.removeTopic, [removeTopicData])
|
||||
})
|
||||
this.on('noLongerPrivate', function () {
|
||||
var newTopicData = {
|
||||
|
@ -343,10 +348,10 @@ Metamaps.Backbone.init = function () {
|
|||
mappableid: this.id
|
||||
}
|
||||
|
||||
$(document).trigger(Metamaps.JIT.events.newTopic, [newTopicData])
|
||||
$(document).trigger(JIT.events.newTopic, [newTopicData])
|
||||
})
|
||||
|
||||
this.on('change:metacode_id', Metamaps.Filter.checkMetacodes, this)
|
||||
this.on('change:metacode_id', Filter.checkMetacodes, this)
|
||||
},
|
||||
authorizeToEdit: function (mapper) {
|
||||
if (mapper &&
|
||||
|
@ -367,10 +372,10 @@ Metamaps.Backbone.init = function () {
|
|||
return Metamaps.Metacodes.get(this.get('metacode_id'))
|
||||
},
|
||||
getMapping: function () {
|
||||
if (!Metamaps.Active.Map) return false
|
||||
if (!Active.Map) return false
|
||||
|
||||
return Metamaps.Mappings.findWhere({
|
||||
map_id: Metamaps.Active.Map.id,
|
||||
map_id: Active.Map.id,
|
||||
mappable_type: 'Topic',
|
||||
mappable_id: this.isNew() ? this.cid : this.id
|
||||
})
|
||||
|
@ -383,7 +388,7 @@ Metamaps.Backbone.init = function () {
|
|||
name: this.get('name')
|
||||
}
|
||||
|
||||
if (Metamaps.Active.Map) {
|
||||
if (Active.Map) {
|
||||
mapping = this.getMapping()
|
||||
node.data = {
|
||||
$mapping: null,
|
||||
|
@ -398,7 +403,7 @@ Metamaps.Backbone.init = function () {
|
|||
var node = this.get('node')
|
||||
node.setData('topic', this)
|
||||
|
||||
if (Metamaps.Active.Map) {
|
||||
if (Active.Map) {
|
||||
mapping = this.getMapping()
|
||||
node.setData('mapping', mapping)
|
||||
}
|
||||
|
@ -406,38 +411,38 @@ Metamaps.Backbone.init = function () {
|
|||
return node
|
||||
},
|
||||
savedEvent: function () {
|
||||
Metamaps.Realtime.sendTopicChange(this)
|
||||
Realtime.sendTopicChange(this)
|
||||
},
|
||||
updateViews: function () {
|
||||
var onPageWithTopicCard = Metamaps.Active.Map || Metamaps.Active.Topic
|
||||
var onPageWithTopicCard = Active.Map || Active.Topic
|
||||
var node = this.get('node')
|
||||
// update topic card, if this topic is the one open there
|
||||
if (onPageWithTopicCard && this == Metamaps.TopicCard.openTopicCard) {
|
||||
Metamaps.TopicCard.showCard(node)
|
||||
if (onPageWithTopicCard && this == TopicCard.openTopicCard) {
|
||||
TopicCard.showCard(node)
|
||||
}
|
||||
|
||||
// update the node on the map
|
||||
if (onPageWithTopicCard && node) {
|
||||
node.name = this.get('name')
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Visualize.mGraph.plot()
|
||||
}
|
||||
},
|
||||
updateCardView: function () {
|
||||
var onPageWithTopicCard = Metamaps.Active.Map || Metamaps.Active.Topic
|
||||
var onPageWithTopicCard = Active.Map || Active.Topic
|
||||
var node = this.get('node')
|
||||
// update topic card, if this topic is the one open there
|
||||
if (onPageWithTopicCard && this == Metamaps.TopicCard.openTopicCard) {
|
||||
Metamaps.TopicCard.showCard(node)
|
||||
if (onPageWithTopicCard && this == TopicCard.openTopicCard) {
|
||||
TopicCard.showCard(node)
|
||||
}
|
||||
},
|
||||
updateNodeView: function () {
|
||||
var onPageWithTopicCard = Metamaps.Active.Map || Metamaps.Active.Topic
|
||||
var onPageWithTopicCard = Active.Map || Active.Topic
|
||||
var node = this.get('node')
|
||||
|
||||
// update the node on the map
|
||||
if (onPageWithTopicCard && node) {
|
||||
node.name = this.get('name')
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Visualize.mGraph.plot()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -485,8 +490,8 @@ Metamaps.Backbone.init = function () {
|
|||
initialize: function () {
|
||||
if (this.isNew()) {
|
||||
this.set({
|
||||
'user_id': Metamaps.Active.Mapper.id,
|
||||
'permission': Metamaps.Active.Map ? Metamaps.Active.Map.get('permission') : 'commons',
|
||||
'user_id': Active.Mapper.id,
|
||||
'permission': Active.Map ? Active.Map.get('permission') : 'commons',
|
||||
'category': 'from-to'
|
||||
})
|
||||
}
|
||||
|
@ -500,15 +505,15 @@ Metamaps.Backbone.init = function () {
|
|||
mappableid: this.id
|
||||
}
|
||||
|
||||
$(document).trigger(Metamaps.JIT.events.newSynapse, [newSynapseData])
|
||||
$(document).trigger(JIT.events.newSynapse, [newSynapseData])
|
||||
})
|
||||
this.on('nowPrivate', function () {
|
||||
$(document).trigger(Metamaps.JIT.events.removeSynapse, [{
|
||||
$(document).trigger(JIT.events.removeSynapse, [{
|
||||
mappableid: this.id
|
||||
}])
|
||||
})
|
||||
|
||||
this.on('change:desc', Metamaps.Filter.checkSynapses, this)
|
||||
this.on('change:desc', Filter.checkSynapses, this)
|
||||
},
|
||||
prepareLiForFilter: function () {
|
||||
var li = ''
|
||||
|
@ -542,10 +547,10 @@ Metamaps.Backbone.init = function () {
|
|||
] : false
|
||||
},
|
||||
getMapping: function () {
|
||||
if (!Metamaps.Active.Map) return false
|
||||
if (!Active.Map) return false
|
||||
|
||||
return Metamaps.Mappings.findWhere({
|
||||
map_id: Metamaps.Active.Map.id,
|
||||
map_id: Active.Map.id,
|
||||
mappable_type: 'Synapse',
|
||||
mappable_id: this.isNew() ? this.cid : this.id
|
||||
})
|
||||
|
@ -563,7 +568,7 @@ Metamaps.Backbone.init = function () {
|
|||
}
|
||||
}
|
||||
|
||||
if (Metamaps.Active.Map) {
|
||||
if (Active.Map) {
|
||||
mapping = providedMapping || this.getMapping()
|
||||
mappingID = mapping.isNew() ? mapping.cid : mapping.id
|
||||
edge.data.$mappings = []
|
||||
|
@ -577,7 +582,7 @@ Metamaps.Backbone.init = function () {
|
|||
var edge = this.get('edge')
|
||||
edge.getData('synapses').push(this)
|
||||
|
||||
if (Metamaps.Active.Map) {
|
||||
if (Active.Map) {
|
||||
mapping = this.getMapping()
|
||||
edge.getData('mappings').push(mapping)
|
||||
}
|
||||
|
@ -585,28 +590,28 @@ Metamaps.Backbone.init = function () {
|
|||
return edge
|
||||
},
|
||||
savedEvent: function () {
|
||||
Metamaps.Realtime.sendSynapseChange(this)
|
||||
Realtime.sendSynapseChange(this)
|
||||
},
|
||||
updateViews: function () {
|
||||
this.updateCardView()
|
||||
this.updateEdgeView()
|
||||
},
|
||||
updateCardView: function () {
|
||||
var onPageWithSynapseCard = Metamaps.Active.Map || Metamaps.Active.Topic
|
||||
var onPageWithSynapseCard = Active.Map || Active.Topic
|
||||
var edge = this.get('edge')
|
||||
|
||||
// update synapse card, if this synapse is the one open there
|
||||
if (onPageWithSynapseCard && edge == Metamaps.SynapseCard.openSynapseCard) {
|
||||
Metamaps.SynapseCard.showCard(edge)
|
||||
if (onPageWithSynapseCard && edge == SynapseCard.openSynapseCard) {
|
||||
SynapseCard.showCard(edge)
|
||||
}
|
||||
},
|
||||
updateEdgeView: function () {
|
||||
var onPageWithSynapseCard = Metamaps.Active.Map || Metamaps.Active.Topic
|
||||
var onPageWithSynapseCard = Active.Map || Active.Topic
|
||||
var edge = this.get('edge')
|
||||
|
||||
// update the edge on the map
|
||||
if (onPageWithSynapseCard && edge) {
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Visualize.mGraph.plot()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -625,20 +630,20 @@ Metamaps.Backbone.init = function () {
|
|||
initialize: function () {
|
||||
if (this.isNew()) {
|
||||
this.set({
|
||||
'user_id': Metamaps.Active.Mapper.id,
|
||||
'map_id': Metamaps.Active.Map ? Metamaps.Active.Map.id : null
|
||||
'user_id': Active.Mapper.id,
|
||||
'map_id': Active.Map ? Active.Map.id : null
|
||||
})
|
||||
}
|
||||
},
|
||||
getMap: function () {
|
||||
return Metamaps.Map.get(this.get('map_id'))
|
||||
return Map.get(this.get('map_id'))
|
||||
},
|
||||
getTopic: function () {
|
||||
if (this.get('mappable_type') === 'Topic') return Metamaps.Topic.get(this.get('mappable_id'))
|
||||
if (this.get('mappable_type') === 'Topic') return Topic.get(this.get('mappable_id'))
|
||||
else return false
|
||||
},
|
||||
getSynapse: function () {
|
||||
if (this.get('mappable_type') === 'Synapse') return Metamaps.Synapse.get(this.get('mappable_id'))
|
||||
if (this.get('mappable_type') === 'Synapse') return Synapse.get(this.get('mappable_id'))
|
||||
else return false
|
||||
}
|
||||
})
|
||||
|
@ -661,36 +666,38 @@ Metamaps.Backbone.init = function () {
|
|||
// this is for topic view
|
||||
Metamaps.Creators = Metamaps.Creators ? new self.MapperCollection(Metamaps.Creators) : new self.MapperCollection()
|
||||
|
||||
if (Metamaps.Active.Map) {
|
||||
if (Active.Map) {
|
||||
Metamaps.Mappings = Metamaps.Mappings ? new self.MappingCollection(Metamaps.Mappings) : new self.MappingCollection()
|
||||
|
||||
Metamaps.Active.Map = new self.Map(Metamaps.Active.Map)
|
||||
Active.Map = new self.Map(Active.Map)
|
||||
}
|
||||
|
||||
if (Metamaps.Active.Topic) Metamaps.Active.Topic = new self.Topic(Metamaps.Active.Topic)
|
||||
if (Active.Topic) Active.Topic = new self.Topic(Active.Topic)
|
||||
|
||||
// attach collection event listeners
|
||||
self.attachCollectionEvents = function () {
|
||||
Metamaps.Topics.on('add remove', function (topic) {
|
||||
Metamaps.Map.InfoBox.updateNumbers()
|
||||
Metamaps.Filter.checkMetacodes()
|
||||
Metamaps.Filter.checkMappers()
|
||||
InfoBox.updateNumbers()
|
||||
Filter.checkMetacodes()
|
||||
Filter.checkMappers()
|
||||
})
|
||||
|
||||
Metamaps.Synapses.on('add remove', function (synapse) {
|
||||
Metamaps.Map.InfoBox.updateNumbers()
|
||||
Metamaps.Filter.checkSynapses()
|
||||
Metamaps.Filter.checkMappers()
|
||||
InfoBox.updateNumbers()
|
||||
Filter.checkSynapses()
|
||||
Filter.checkMappers()
|
||||
})
|
||||
|
||||
if (Metamaps.Active.Map) {
|
||||
if (Active.Map) {
|
||||
Metamaps.Mappings.on('add remove', function (mapping) {
|
||||
Metamaps.Map.InfoBox.updateNumbers()
|
||||
Metamaps.Filter.checkSynapses()
|
||||
Metamaps.Filter.checkMetacodes()
|
||||
Metamaps.Filter.checkMappers()
|
||||
InfoBox.updateNumbers()
|
||||
Filter.checkSynapses()
|
||||
Filter.checkMetacodes()
|
||||
Filter.checkMappers()
|
||||
})
|
||||
}
|
||||
}
|
||||
self.attachCollectionEvents()
|
||||
}; // end Metamaps.Backbone.init
|
||||
}; // end _Backbone.init
|
||||
|
||||
export default _Backbone
|
|
@ -1,154 +1,156 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import _ from 'lodash'
|
||||
|
||||
import Active from './Active'
|
||||
import Filter from './Filter'
|
||||
import GlobalUI from './GlobalUI'
|
||||
import JIT from './JIT'
|
||||
import Mouse from './Mouse'
|
||||
import Selected from './Selected'
|
||||
import Settings from './Settings'
|
||||
import Visualize from './Visualize'
|
||||
|
||||
/*
|
||||
* Metamaps.Control.js.erb
|
||||
* Metamaps.Control.js
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.Control
|
||||
* - Metamaps.Filter
|
||||
* - Metamaps.GlobalUI
|
||||
* - Metamaps.JIT
|
||||
* - Metamaps.Mappings
|
||||
* - Metamaps.Metacodes
|
||||
* - Metamaps.Mouse
|
||||
* - Metamaps.Selected
|
||||
* - Metamaps.Settings
|
||||
* - Metamaps.Synapses
|
||||
* - Metamaps.Topics
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
|
||||
Metamaps.Control = {
|
||||
const Control = {
|
||||
init: function () {},
|
||||
selectNode: function (node, e) {
|
||||
var filtered = node.getData('alpha') === 0
|
||||
|
||||
if (filtered || Metamaps.Selected.Nodes.indexOf(node) != -1) return
|
||||
if (filtered || Selected.Nodes.indexOf(node) != -1) return
|
||||
node.selected = true
|
||||
node.setData('dim', 30, 'current')
|
||||
Metamaps.Selected.Nodes.push(node)
|
||||
Selected.Nodes.push(node)
|
||||
},
|
||||
deselectAllNodes: function () {
|
||||
var l = Metamaps.Selected.Nodes.length
|
||||
var l = Selected.Nodes.length
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var node = Metamaps.Selected.Nodes[i]
|
||||
Metamaps.Control.deselectNode(node)
|
||||
var node = Selected.Nodes[i]
|
||||
Control.deselectNode(node)
|
||||
}
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Visualize.mGraph.plot()
|
||||
},
|
||||
deselectNode: function (node) {
|
||||
delete node.selected
|
||||
node.setData('dim', 25, 'current')
|
||||
|
||||
// remove the node
|
||||
Metamaps.Selected.Nodes.splice(
|
||||
Metamaps.Selected.Nodes.indexOf(node), 1)
|
||||
Selected.Nodes.splice(
|
||||
Selected.Nodes.indexOf(node), 1)
|
||||
},
|
||||
deleteSelected: function () {
|
||||
if (!Metamaps.Active.Map) return
|
||||
if (!Active.Map) return
|
||||
|
||||
var n = Metamaps.Selected.Nodes.length
|
||||
var e = Metamaps.Selected.Edges.length
|
||||
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 text = 'You have ' + ntext + ' and ' + etext + ' selected. '
|
||||
|
||||
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
|
||||
|
||||
if (!authorized) {
|
||||
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
return
|
||||
}
|
||||
|
||||
var r = confirm(text + 'Are you sure you want to permanently delete them all? This will remove them from all maps they appear on.')
|
||||
if (r == true) {
|
||||
Metamaps.Control.deleteSelectedEdges()
|
||||
Metamaps.Control.deleteSelectedNodes()
|
||||
Control.deleteSelectedEdges()
|
||||
Control.deleteSelectedNodes()
|
||||
}
|
||||
},
|
||||
deleteSelectedNodes: function () { // refers to deleting topics permanently
|
||||
if (!Metamaps.Active.Map) return
|
||||
if (!Active.Map) return
|
||||
|
||||
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
|
||||
|
||||
if (!authorized) {
|
||||
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
return
|
||||
}
|
||||
|
||||
var l = Metamaps.Selected.Nodes.length
|
||||
var l = Selected.Nodes.length
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var node = Metamaps.Selected.Nodes[i]
|
||||
Metamaps.Control.deleteNode(node.id)
|
||||
var node = Selected.Nodes[i]
|
||||
Control.deleteNode(node.id)
|
||||
}
|
||||
},
|
||||
deleteNode: function (nodeid) { // refers to deleting topics permanently
|
||||
if (!Metamaps.Active.Map) return
|
||||
if (!Active.Map) return
|
||||
|
||||
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
|
||||
|
||||
if (!authorized) {
|
||||
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
return
|
||||
}
|
||||
|
||||
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid)
|
||||
var node = Visualize.mGraph.graph.getNode(nodeid)
|
||||
var topic = node.getData('topic')
|
||||
|
||||
var permToDelete = Metamaps.Active.Mapper.id === topic.get('user_id') || Metamaps.Active.Mapper.get('admin')
|
||||
var permToDelete = Active.Mapper.id === topic.get('user_id') || Active.Mapper.get('admin')
|
||||
if (permToDelete) {
|
||||
var mappableid = topic.id
|
||||
var mapping = node.getData('mapping')
|
||||
topic.destroy()
|
||||
Metamaps.Mappings.remove(mapping)
|
||||
$(document).trigger(Metamaps.JIT.events.deleteTopic, [{
|
||||
$(document).trigger(JIT.events.deleteTopic, [{
|
||||
mappableid: mappableid
|
||||
}])
|
||||
Metamaps.Control.hideNode(nodeid)
|
||||
Control.hideNode(nodeid)
|
||||
} else {
|
||||
Metamaps.GlobalUI.notifyUser('Only topics you created can be deleted')
|
||||
GlobalUI.notifyUser('Only topics you created can be deleted')
|
||||
}
|
||||
},
|
||||
removeSelectedNodes: function () { // refers to removing topics permanently from a map
|
||||
if (Metamaps.Active.Topic) {
|
||||
if (Active.Topic) {
|
||||
// hideNode will handle synapses as well
|
||||
var nodeids = _.map(Metamaps.Selected.Nodes, function(node) {
|
||||
var nodeids = _.map(Selected.Nodes, function(node) {
|
||||
return node.id
|
||||
})
|
||||
_.each(nodeids, function(nodeid) {
|
||||
if (Metamaps.Active.Topic.id !== nodeid) {
|
||||
if (Active.Topic.id !== nodeid) {
|
||||
Metamaps.Topics.remove(nodeid)
|
||||
Metamaps.Control.hideNode(nodeid)
|
||||
Control.hideNode(nodeid)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!Metamaps.Active.Map) return
|
||||
if (!Active.Map) return
|
||||
|
||||
var l = Metamaps.Selected.Nodes.length,
|
||||
var l = Selected.Nodes.length,
|
||||
i,
|
||||
node,
|
||||
authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
authorized = Active.Map.authorizeToEdit(Active.Mapper)
|
||||
|
||||
if (!authorized) {
|
||||
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
return
|
||||
}
|
||||
|
||||
for (i = l - 1; i >= 0; i -= 1) {
|
||||
node = Metamaps.Selected.Nodes[i]
|
||||
Metamaps.Control.removeNode(node.id)
|
||||
node = Selected.Nodes[i]
|
||||
Control.removeNode(node.id)
|
||||
}
|
||||
},
|
||||
removeNode: function (nodeid) { // refers to removing topics permanently from a map
|
||||
if (!Metamaps.Active.Map) return
|
||||
if (!Active.Map) return
|
||||
|
||||
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid)
|
||||
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
|
||||
var node = Visualize.mGraph.graph.getNode(nodeid)
|
||||
|
||||
if (!authorized) {
|
||||
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -157,116 +159,116 @@ Metamaps.Control = {
|
|||
var mapping = node.getData('mapping')
|
||||
mapping.destroy()
|
||||
Metamaps.Topics.remove(topic)
|
||||
$(document).trigger(Metamaps.JIT.events.removeTopic, [{
|
||||
$(document).trigger(JIT.events.removeTopic, [{
|
||||
mappableid: mappableid
|
||||
}])
|
||||
Metamaps.Control.hideNode(nodeid)
|
||||
Control.hideNode(nodeid)
|
||||
},
|
||||
hideSelectedNodes: function () {
|
||||
var l = Metamaps.Selected.Nodes.length,
|
||||
var l = Selected.Nodes.length,
|
||||
i,
|
||||
node
|
||||
|
||||
for (i = l - 1; i >= 0; i -= 1) {
|
||||
node = Metamaps.Selected.Nodes[i]
|
||||
Metamaps.Control.hideNode(node.id)
|
||||
node = Selected.Nodes[i]
|
||||
Control.hideNode(node.id)
|
||||
}
|
||||
},
|
||||
hideNode: function (nodeid) {
|
||||
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid)
|
||||
var graph = Metamaps.Visualize.mGraph
|
||||
var node = Visualize.mGraph.graph.getNode(nodeid)
|
||||
var graph = Visualize.mGraph
|
||||
|
||||
Metamaps.Control.deselectNode(node)
|
||||
Control.deselectNode(node)
|
||||
|
||||
node.setData('alpha', 0, 'end')
|
||||
node.eachAdjacency(function (adj) {
|
||||
adj.setData('alpha', 0, 'end')
|
||||
})
|
||||
Metamaps.Visualize.mGraph.fx.animate({
|
||||
Visualize.mGraph.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'
|
||||
],
|
||||
duration: 500
|
||||
})
|
||||
setTimeout(function () {
|
||||
if (nodeid == Metamaps.Visualize.mGraph.root) { // && Metamaps.Visualize.type === "RGraph"
|
||||
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
|
||||
}
|
||||
Metamaps.Visualize.mGraph.graph.removeNode(nodeid)
|
||||
Visualize.mGraph.graph.removeNode(nodeid)
|
||||
}, 500)
|
||||
Metamaps.Filter.checkMetacodes()
|
||||
Metamaps.Filter.checkMappers()
|
||||
Filter.checkMetacodes()
|
||||
Filter.checkMappers()
|
||||
},
|
||||
selectEdge: function (edge) {
|
||||
var filtered = edge.getData('alpha') === 0; // don't select if the edge is filtered
|
||||
|
||||
if (filtered || Metamaps.Selected.Edges.indexOf(edge) != -1) return
|
||||
if (filtered || Selected.Edges.indexOf(edge) != -1) return
|
||||
|
||||
var width = Metamaps.Mouse.edgeHoveringOver === edge ? 4 : 2
|
||||
var width = Mouse.edgeHoveringOver === edge ? 4 : 2
|
||||
edge.setDataset('current', {
|
||||
showDesc: true,
|
||||
lineWidth: width,
|
||||
color: Metamaps.Settings.colors.synapses.selected
|
||||
color: Settings.colors.synapses.selected
|
||||
})
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Visualize.mGraph.plot()
|
||||
|
||||
Metamaps.Selected.Edges.push(edge)
|
||||
Selected.Edges.push(edge)
|
||||
},
|
||||
deselectAllEdges: function () {
|
||||
var l = Metamaps.Selected.Edges.length
|
||||
var l = Selected.Edges.length
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var edge = Metamaps.Selected.Edges[i]
|
||||
Metamaps.Control.deselectEdge(edge)
|
||||
var edge = Selected.Edges[i]
|
||||
Control.deselectEdge(edge)
|
||||
}
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Visualize.mGraph.plot()
|
||||
},
|
||||
deselectEdge: function (edge) {
|
||||
edge.setData('showDesc', false, 'current')
|
||||
|
||||
edge.setDataset('current', {
|
||||
lineWidth: 2,
|
||||
color: Metamaps.Settings.colors.synapses.normal
|
||||
color: Settings.colors.synapses.normal
|
||||
})
|
||||
|
||||
if (Metamaps.Mouse.edgeHoveringOver == edge) {
|
||||
if (Mouse.edgeHoveringOver == edge) {
|
||||
edge.setDataset('current', {
|
||||
showDesc: true,
|
||||
lineWidth: 4
|
||||
})
|
||||
}
|
||||
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Visualize.mGraph.plot()
|
||||
|
||||
// remove the edge
|
||||
Metamaps.Selected.Edges.splice(
|
||||
Metamaps.Selected.Edges.indexOf(edge), 1)
|
||||
Selected.Edges.splice(
|
||||
Selected.Edges.indexOf(edge), 1)
|
||||
},
|
||||
deleteSelectedEdges: function () { // refers to deleting topics permanently
|
||||
var edge,
|
||||
l = Metamaps.Selected.Edges.length
|
||||
l = Selected.Edges.length
|
||||
|
||||
if (!Metamaps.Active.Map) return
|
||||
if (!Active.Map) return
|
||||
|
||||
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
|
||||
|
||||
if (!authorized) {
|
||||
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
return
|
||||
}
|
||||
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
edge = Metamaps.Selected.Edges[i]
|
||||
Metamaps.Control.deleteEdge(edge)
|
||||
edge = Selected.Edges[i]
|
||||
Control.deleteEdge(edge)
|
||||
}
|
||||
},
|
||||
deleteEdge: function (edge) {
|
||||
if (!Metamaps.Active.Map) return
|
||||
if (!Active.Map) return
|
||||
|
||||
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
|
||||
|
||||
if (!authorized) {
|
||||
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -275,10 +277,10 @@ Metamaps.Control = {
|
|||
var synapse = edge.getData('synapses')[index]
|
||||
var mapping = edge.getData('mappings')[index]
|
||||
|
||||
var permToDelete = Metamaps.Active.Mapper.id === synapse.get('user_id') || Metamaps.Active.Mapper.get('admin')
|
||||
var permToDelete = Active.Mapper.id === synapse.get('user_id') || Active.Mapper.get('admin')
|
||||
if (permToDelete) {
|
||||
if (edge.getData('synapses').length - 1 === 0) {
|
||||
Metamaps.Control.hideEdge(edge)
|
||||
Control.hideEdge(edge)
|
||||
}
|
||||
var mappableid = synapse.id
|
||||
synapse.destroy()
|
||||
|
@ -290,46 +292,46 @@ Metamaps.Control = {
|
|||
if (edge.getData('displayIndex')) {
|
||||
delete edge.data.$displayIndex
|
||||
}
|
||||
$(document).trigger(Metamaps.JIT.events.deleteSynapse, [{
|
||||
$(document).trigger(JIT.events.deleteSynapse, [{
|
||||
mappableid: mappableid
|
||||
}])
|
||||
} else {
|
||||
Metamaps.GlobalUI.notifyUser('Only synapses you created can be deleted')
|
||||
GlobalUI.notifyUser('Only synapses you created can be deleted')
|
||||
}
|
||||
},
|
||||
removeSelectedEdges: function () {
|
||||
// Topic view is handled by removeSelectedNodes
|
||||
if (!Metamaps.Active.Map) return
|
||||
if (!Active.Map) return
|
||||
|
||||
var l = Metamaps.Selected.Edges.length,
|
||||
var l = Selected.Edges.length,
|
||||
i,
|
||||
edge
|
||||
|
||||
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
|
||||
|
||||
if (!authorized) {
|
||||
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
return
|
||||
}
|
||||
|
||||
for (i = l - 1; i >= 0; i -= 1) {
|
||||
edge = Metamaps.Selected.Edges[i]
|
||||
Metamaps.Control.removeEdge(edge)
|
||||
edge = Selected.Edges[i]
|
||||
Control.removeEdge(edge)
|
||||
}
|
||||
Metamaps.Selected.Edges = [ ]
|
||||
Selected.Edges = [ ]
|
||||
},
|
||||
removeEdge: function (edge) {
|
||||
if (!Metamaps.Active.Map) return
|
||||
if (!Active.Map) return
|
||||
|
||||
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var authorized = Active.Map.authorizeToEdit(Active.Mapper)
|
||||
|
||||
if (!authorized) {
|
||||
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
GlobalUI.notifyUser('Cannot edit Public map.')
|
||||
return
|
||||
}
|
||||
|
||||
if (edge.getData('mappings').length - 1 === 0) {
|
||||
Metamaps.Control.hideEdge(edge)
|
||||
Control.hideEdge(edge)
|
||||
}
|
||||
|
||||
var index = edge.getData('displayIndex') ? edge.getData('displayIndex') : 0
|
||||
|
@ -346,51 +348,51 @@ Metamaps.Control = {
|
|||
if (edge.getData('displayIndex')) {
|
||||
delete edge.data.$displayIndex
|
||||
}
|
||||
$(document).trigger(Metamaps.JIT.events.removeSynapse, [{
|
||||
$(document).trigger(JIT.events.removeSynapse, [{
|
||||
mappableid: mappableid
|
||||
}])
|
||||
},
|
||||
hideSelectedEdges: function () {
|
||||
var edge,
|
||||
l = Metamaps.Selected.Edges.length,
|
||||
l = Selected.Edges.length,
|
||||
i
|
||||
for (i = l - 1; i >= 0; i -= 1) {
|
||||
edge = Metamaps.Selected.Edges[i]
|
||||
Metamaps.Control.hideEdge(edge)
|
||||
edge = Selected.Edges[i]
|
||||
Control.hideEdge(edge)
|
||||
}
|
||||
Metamaps.Selected.Edges = [ ]
|
||||
Selected.Edges = [ ]
|
||||
},
|
||||
hideEdge: function (edge) {
|
||||
var from = edge.nodeFrom.id
|
||||
var to = edge.nodeTo.id
|
||||
edge.setData('alpha', 0, 'end')
|
||||
Metamaps.Control.deselectEdge(edge)
|
||||
Metamaps.Visualize.mGraph.fx.animate({
|
||||
Control.deselectEdge(edge)
|
||||
Visualize.mGraph.fx.animate({
|
||||
modes: ['edge-property:alpha'],
|
||||
duration: 500
|
||||
})
|
||||
setTimeout(function () {
|
||||
Metamaps.Visualize.mGraph.graph.removeAdjacence(from, to)
|
||||
Visualize.mGraph.graph.removeAdjacence(from, to)
|
||||
}, 500)
|
||||
Metamaps.Filter.checkSynapses()
|
||||
Metamaps.Filter.checkMappers()
|
||||
Filter.checkSynapses()
|
||||
Filter.checkMappers()
|
||||
},
|
||||
updateSelectedPermissions: function (permission) {
|
||||
var edge, synapse, node, topic
|
||||
|
||||
Metamaps.GlobalUI.notifyUser('Working...')
|
||||
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,
|
||||
sCount = 0
|
||||
|
||||
// change the permission of the selected synapses, if logged in user is the original creator
|
||||
var l = Metamaps.Selected.Edges.length
|
||||
var l = Selected.Edges.length
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
edge = Metamaps.Selected.Edges[i]
|
||||
edge = Selected.Edges[i]
|
||||
synapse = edge.getData('synapses')[0]
|
||||
|
||||
if (synapse.authorizePermissionChange(Metamaps.Active.Mapper)) {
|
||||
if (synapse.authorizePermissionChange(Active.Mapper)) {
|
||||
synapse.save({
|
||||
permission: permission
|
||||
})
|
||||
|
@ -399,12 +401,12 @@ Metamaps.Control = {
|
|||
}
|
||||
|
||||
// change the permission of the selected topics, if logged in user is the original creator
|
||||
var l = Metamaps.Selected.Nodes.length
|
||||
var l = Selected.Nodes.length
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
node = Metamaps.Selected.Nodes[i]
|
||||
node = Selected.Nodes[i]
|
||||
topic = node.getData('topic')
|
||||
|
||||
if (topic.authorizePermissionChange(Metamaps.Active.Mapper)) {
|
||||
if (topic.authorizePermissionChange(Active.Mapper)) {
|
||||
topic.save({
|
||||
permission: permission
|
||||
})
|
||||
|
@ -416,12 +418,12 @@ Metamaps.Control = {
|
|||
var sString = sCount == 1 ? (sCount.toString() + ' synapse') : (sCount.toString() + ' synapses')
|
||||
|
||||
var message = nString + sString + ' you created updated to ' + permission
|
||||
Metamaps.GlobalUI.notifyUser(message)
|
||||
GlobalUI.notifyUser(message)
|
||||
},
|
||||
updateSelectedMetacodes: function (metacode_id) {
|
||||
var node, topic
|
||||
|
||||
Metamaps.GlobalUI.notifyUser('Working...')
|
||||
GlobalUI.notifyUser('Working...')
|
||||
|
||||
var metacode = Metamaps.Metacodes.get(metacode_id)
|
||||
|
||||
|
@ -429,12 +431,12 @@ Metamaps.Control = {
|
|||
var nCount = 0
|
||||
|
||||
// change the permission of the selected topics, if logged in user is the original creator
|
||||
var l = Metamaps.Selected.Nodes.length
|
||||
var l = Selected.Nodes.length
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
node = Metamaps.Selected.Nodes[i]
|
||||
node = Selected.Nodes[i]
|
||||
topic = node.getData('topic')
|
||||
|
||||
if (topic.authorizeToEdit(Metamaps.Active.Mapper)) {
|
||||
if (topic.authorizeToEdit(Active.Mapper)) {
|
||||
topic.save({
|
||||
'metacode_id': metacode_id
|
||||
})
|
||||
|
@ -445,7 +447,9 @@ Metamaps.Control = {
|
|||
var nString = nCount == 1 ? (nCount.toString() + ' topic') : (nCount.toString() + ' topics')
|
||||
|
||||
var message = nString + ' you can edit updated to ' + metacode.get('name')
|
||||
Metamaps.GlobalUI.notifyUser(message)
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
GlobalUI.notifyUser(message)
|
||||
Visualize.mGraph.plot()
|
||||
},
|
||||
}; // end Metamaps.Control
|
||||
}
|
||||
|
||||
export default Control
|
|
@ -1,20 +1,21 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import Mouse from './Mouse'
|
||||
import Selected from './Selected'
|
||||
import Synapse from './Synapse'
|
||||
import Topic from './Topic'
|
||||
import Visualize from './Visualize'
|
||||
import GlobalUI from './GlobalUI'
|
||||
|
||||
/*
|
||||
* Metamaps.Create.js
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Backbone
|
||||
* - Metamaps.GlobalUI
|
||||
* - Metamaps.Metacodes
|
||||
* - Metamaps.Mouse
|
||||
* - Metamaps.Selected
|
||||
* - Metamaps.Synapse
|
||||
* - Metamaps.Topic
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
|
||||
Metamaps.Create = {
|
||||
const Create = {
|
||||
isSwitchingSet: false, // indicates whether the metacode set switch lightbox is open
|
||||
selectedMetacodeSet: null,
|
||||
selectedMetacodeSetIndex: null,
|
||||
|
@ -23,7 +24,7 @@ Metamaps.Create = {
|
|||
selectedMetacodes: [],
|
||||
newSelectedMetacodes: [],
|
||||
init: function () {
|
||||
var self = Metamaps.Create
|
||||
var self = Create
|
||||
self.newTopic.init()
|
||||
self.newSynapse.init()
|
||||
|
||||
|
@ -36,7 +37,7 @@ Metamaps.Create = {
|
|||
$('.customMetacodeList li').click(self.toggleMetacodeSelected) // within the custom metacode set tab
|
||||
},
|
||||
toggleMetacodeSelected: function () {
|
||||
var self = Metamaps.Create
|
||||
var self = Create
|
||||
|
||||
if ($(this).attr('class') != 'toggledOff') {
|
||||
$(this).addClass('toggledOff')
|
||||
|
@ -51,29 +52,29 @@ Metamaps.Create = {
|
|||
}
|
||||
},
|
||||
updateMetacodeSet: function (set, index, custom) {
|
||||
if (custom && Metamaps.Create.newSelectedMetacodes.length == 0) {
|
||||
if (custom && Create.newSelectedMetacodes.length == 0) {
|
||||
alert('Please select at least one metacode to use!')
|
||||
return false
|
||||
}
|
||||
|
||||
var codesToSwitchToIds
|
||||
var metacodeModels = new Metamaps.Backbone.MetacodeCollection()
|
||||
Metamaps.Create.selectedMetacodeSetIndex = index
|
||||
Metamaps.Create.selectedMetacodeSet = 'metacodeset-' + set
|
||||
Create.selectedMetacodeSetIndex = index
|
||||
Create.selectedMetacodeSet = 'metacodeset-' + set
|
||||
|
||||
if (!custom) {
|
||||
codesToSwitchToIds = $('#metacodeSwitchTabs' + set).attr('data-metacodes').split(',')
|
||||
$('.customMetacodeList li').addClass('toggledOff')
|
||||
Metamaps.Create.selectedMetacodes = []
|
||||
Metamaps.Create.selectedMetacodeNames = []
|
||||
Metamaps.Create.newSelectedMetacodes = []
|
||||
Metamaps.Create.newSelectedMetacodeNames = []
|
||||
Create.selectedMetacodes = []
|
||||
Create.selectedMetacodeNames = []
|
||||
Create.newSelectedMetacodes = []
|
||||
Create.newSelectedMetacodeNames = []
|
||||
}
|
||||
else if (custom) {
|
||||
// uses .slice to avoid setting the two arrays to the same actual array
|
||||
Metamaps.Create.selectedMetacodes = Metamaps.Create.newSelectedMetacodes.slice(0)
|
||||
Metamaps.Create.selectedMetacodeNames = Metamaps.Create.newSelectedMetacodeNames.slice(0)
|
||||
codesToSwitchToIds = Metamaps.Create.selectedMetacodes.slice(0)
|
||||
Create.selectedMetacodes = Create.newSelectedMetacodes.slice(0)
|
||||
Create.selectedMetacodeNames = Create.newSelectedMetacodeNames.slice(0)
|
||||
codesToSwitchToIds = Create.selectedMetacodes.slice(0)
|
||||
}
|
||||
|
||||
// sort by name
|
||||
|
@ -100,12 +101,12 @@ Metamaps.Create = {
|
|||
bringToFront: true
|
||||
})
|
||||
|
||||
Metamaps.GlobalUI.closeLightbox()
|
||||
GlobalUI.closeLightbox()
|
||||
$('#topic_name').focus()
|
||||
|
||||
var mdata = {
|
||||
'metacodes': {
|
||||
'value': custom ? Metamaps.Create.selectedMetacodes.toString() : Metamaps.Create.selectedMetacodeSet
|
||||
'value': custom ? Create.selectedMetacodes.toString() : Create.selectedMetacodeSet
|
||||
}
|
||||
}
|
||||
$.ajax({
|
||||
|
@ -123,7 +124,7 @@ Metamaps.Create = {
|
|||
},
|
||||
|
||||
cancelMetacodeSetSwitch: function () {
|
||||
var self = Metamaps.Create
|
||||
var self = Create
|
||||
self.isSwitchingSet = false
|
||||
|
||||
if (self.selectedMetacodeSet != 'metacodeset-custom') {
|
||||
|
@ -148,17 +149,17 @@ Metamaps.Create = {
|
|||
newTopic: {
|
||||
init: function () {
|
||||
$('#topic_name').keyup(function () {
|
||||
Metamaps.Create.newTopic.name = $(this).val()
|
||||
Create.newTopic.name = $(this).val()
|
||||
})
|
||||
|
||||
$('.pinCarousel').click(function() {
|
||||
if (Metamaps.Create.newTopic.pinned) {
|
||||
if (Create.newTopic.pinned) {
|
||||
$('.pinCarousel').removeClass('isPinned')
|
||||
Metamaps.Create.newTopic.pinned = false
|
||||
Create.newTopic.pinned = false
|
||||
}
|
||||
else {
|
||||
$('.pinCarousel').addClass('isPinned')
|
||||
Metamaps.Create.newTopic.pinned = true
|
||||
Create.newTopic.pinned = true
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -192,7 +193,7 @@ Metamaps.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) {
|
||||
Metamaps.Topic.getTopicFromAutocomplete(datum.id)
|
||||
Topic.getTopicFromAutocomplete(datum.id)
|
||||
})
|
||||
|
||||
// initialize metacode spinner and then hide it
|
||||
|
@ -220,24 +221,24 @@ Metamaps.Create = {
|
|||
$('#new_topic').fadeIn('fast', function () {
|
||||
$('#topic_name').focus()
|
||||
})
|
||||
Metamaps.Create.newTopic.beingCreated = true
|
||||
Metamaps.Create.newTopic.name = ''
|
||||
Create.newTopic.beingCreated = true
|
||||
Create.newTopic.name = ''
|
||||
},
|
||||
hide: function (force) {
|
||||
if (force || !Metamaps.Create.newTopic.pinned) {
|
||||
if (force || !Create.newTopic.pinned) {
|
||||
$('#new_topic').fadeOut('fast')
|
||||
Metamaps.Create.newTopic.beingCreated = false
|
||||
Create.newTopic.beingCreated = false
|
||||
}
|
||||
if (force) {
|
||||
$('.pinCarousel').removeClass('isPinned')
|
||||
Metamaps.Create.newTopic.pinned = false
|
||||
Create.newTopic.pinned = false
|
||||
}
|
||||
$('#topic_name').typeahead('val', '')
|
||||
}
|
||||
},
|
||||
newSynapse: {
|
||||
init: function () {
|
||||
var self = Metamaps.Create.newSynapse
|
||||
var self = Create.newSynapse
|
||||
|
||||
var synapseBloodhound = new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||
|
@ -253,8 +254,8 @@ Metamaps.Create = {
|
|||
remote: {
|
||||
url: '/search/synapses?topic1id=%TOPIC1&topic2id=%TOPIC2',
|
||||
prepare: function (query, settings) {
|
||||
var self = Metamaps.Create.newSynapse
|
||||
if (Metamaps.Selected.Nodes.length < 2) {
|
||||
var self = Create.newSynapse
|
||||
if (Selected.Nodes.length < 2) {
|
||||
settings.url = settings.url.replace('%TOPIC1', self.topic1id).replace('%TOPIC2', self.topic2id)
|
||||
return settings
|
||||
} else {
|
||||
|
@ -299,23 +300,23 @@ Metamaps.Create = {
|
|||
if (e.keyCode === BACKSPACE && $(this).val() === '' ||
|
||||
e.keyCode === DELETE && $(this).val() === '' ||
|
||||
e.keyCode === ESC) {
|
||||
Metamaps.Create.newSynapse.hide()
|
||||
Create.newSynapse.hide()
|
||||
} // if
|
||||
Metamaps.Create.newSynapse.description = $(this).val()
|
||||
Create.newSynapse.description = $(this).val()
|
||||
})
|
||||
|
||||
$('#synapse_desc').focusout(function () {
|
||||
if (Metamaps.Create.newSynapse.beingCreated) {
|
||||
Metamaps.Synapse.createSynapseLocally()
|
||||
if (Create.newSynapse.beingCreated) {
|
||||
Synapse.createSynapseLocally()
|
||||
}
|
||||
})
|
||||
|
||||
$('#synapse_desc').bind('typeahead:select', function (event, datum, dataset) {
|
||||
if (datum.id) { // if they clicked on an existing synapse get it
|
||||
Metamaps.Synapse.getSynapseFromAutocomplete(datum.id)
|
||||
Synapse.getSynapseFromAutocomplete(datum.id)
|
||||
} else {
|
||||
Metamaps.Create.newSynapse.description = datum.value
|
||||
Metamaps.Synapse.createSynapseLocally()
|
||||
Create.newSynapse.description = datum.value
|
||||
Synapse.createSynapseLocally()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -328,17 +329,19 @@ Metamaps.Create = {
|
|||
$('#new_synapse').fadeIn(100, function () {
|
||||
$('#synapse_desc').focus()
|
||||
})
|
||||
Metamaps.Create.newSynapse.beingCreated = true
|
||||
Create.newSynapse.beingCreated = true
|
||||
},
|
||||
hide: function () {
|
||||
$('#new_synapse').fadeOut('fast')
|
||||
$('#synapse_desc').typeahead('val', '')
|
||||
Metamaps.Create.newSynapse.beingCreated = false
|
||||
Metamaps.Create.newTopic.addSynapse = false
|
||||
Metamaps.Create.newSynapse.topic1id = 0
|
||||
Metamaps.Create.newSynapse.topic2id = 0
|
||||
Metamaps.Mouse.synapseStartCoordinates = []
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Create.newSynapse.beingCreated = false
|
||||
Create.newTopic.addSynapse = false
|
||||
Create.newSynapse.topic1id = 0
|
||||
Create.newSynapse.topic2id = 0
|
||||
Mouse.synapseStartCoordinates = []
|
||||
Visualize.mGraph.plot()
|
||||
},
|
||||
}
|
||||
}; // end Metamaps.Create
|
||||
}
|
||||
|
||||
export default Create
|
6
frontend/src/Metamaps/Debug.js
Normal file
6
frontend/src/Metamaps/Debug.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
const Debug = (arg = window.Metamaps) => {
|
||||
console.debug(arg)
|
||||
console.debug(`Metamaps Version: ${arg.VERSION}`)
|
||||
}
|
||||
|
||||
export default Debug
|
|
@ -1,21 +1,24 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import _ from 'lodash'
|
||||
|
||||
import Active from './Active'
|
||||
import Control from './Control'
|
||||
import GlobalUI from './GlobalUI'
|
||||
import Settings from './Settings'
|
||||
import Visualize from './Visualize'
|
||||
|
||||
/*
|
||||
* Metamaps.Filter.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.Control
|
||||
* - Metamaps.Creators
|
||||
* - Metamaps.GlobalUI
|
||||
* - Metamaps.Mappers
|
||||
* - Metamaps.Metacodes
|
||||
* - Metamaps.Settings
|
||||
* - Metamaps.Synapses
|
||||
* - Metamaps.Topics
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
Metamaps.Filter = {
|
||||
const Filter = {
|
||||
filters: {
|
||||
name: '',
|
||||
metacodes: [],
|
||||
|
@ -30,7 +33,7 @@ Metamaps.Filter = {
|
|||
isOpen: false,
|
||||
changing: false,
|
||||
init: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
|
||||
$('.sidebarFilterIcon').click(self.toggleBox)
|
||||
|
||||
|
@ -45,7 +48,7 @@ Metamaps.Filter = {
|
|||
self.getFilterData()
|
||||
},
|
||||
toggleBox: function (event) {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
|
||||
if (self.isOpen) self.close()
|
||||
else self.open()
|
||||
|
@ -53,9 +56,9 @@ Metamaps.Filter = {
|
|||
event.stopPropagation()
|
||||
},
|
||||
open: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
|
||||
Metamaps.GlobalUI.Account.close()
|
||||
GlobalUI.Account.close()
|
||||
$('.sidebarFilterIcon div').addClass('hide')
|
||||
|
||||
if (!self.isOpen && !self.changing) {
|
||||
|
@ -69,7 +72,7 @@ Metamaps.Filter = {
|
|||
}
|
||||
},
|
||||
close: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
$('.sidebarFilterIcon div').removeClass('hide')
|
||||
|
||||
if (!self.changing) {
|
||||
|
@ -82,7 +85,7 @@ Metamaps.Filter = {
|
|||
}
|
||||
},
|
||||
reset: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
|
||||
self.filters.metacodes = []
|
||||
self.filters.mappers = []
|
||||
|
@ -102,7 +105,7 @@ Metamaps.Filter = {
|
|||
But what these function do is load this data into three accessible array within java : metacodes, mappers and synapses
|
||||
*/
|
||||
getFilterData: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
|
||||
var metacode, mapper, synapse
|
||||
|
||||
|
@ -125,7 +128,7 @@ Metamaps.Filter = {
|
|||
})
|
||||
},
|
||||
bindLiClicks: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
$('#filter_by_metacode ul li').unbind().click(self.toggleMetacode)
|
||||
$('#filter_by_mapper ul li').unbind().click(self.toggleMapper)
|
||||
$('#filter_by_synapse ul li').unbind().click(self.toggleSynapse)
|
||||
|
@ -136,7 +139,7 @@ Metamaps.Filter = {
|
|||
@param
|
||||
*/
|
||||
updateFilters: function (collection, propertyToCheck, correlatedModel, filtersToUse, listToModify) {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
|
||||
var newList = []
|
||||
var removed = []
|
||||
|
@ -211,12 +214,12 @@ Metamaps.Filter = {
|
|||
self.bindLiClicks()
|
||||
},
|
||||
checkMetacodes: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
self.updateFilters('Topics', 'metacode_id', 'Metacodes', 'metacodes', 'metacode')
|
||||
},
|
||||
checkMappers: function () {
|
||||
var self = Metamaps.Filter
|
||||
var onMap = Metamaps.Active.Map ? true : false
|
||||
var self = Filter
|
||||
var onMap = Active.Map ? true : false
|
||||
if (onMap) {
|
||||
self.updateFilters('Mappings', 'user_id', 'Mappers', 'mappers', 'mapper')
|
||||
} else {
|
||||
|
@ -225,11 +228,11 @@ Metamaps.Filter = {
|
|||
}
|
||||
},
|
||||
checkSynapses: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
self.updateFilters('Synapses', 'desc', 'Synapses', 'synapses', 'synapse')
|
||||
},
|
||||
filterAllMetacodes: function (e) {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
$('#filter_by_metacode ul li').addClass('toggledOff')
|
||||
$('.showAllMetacodes').removeClass('active')
|
||||
$('.hideAllMetacodes').addClass('active')
|
||||
|
@ -237,7 +240,7 @@ Metamaps.Filter = {
|
|||
self.passFilters()
|
||||
},
|
||||
filterNoMetacodes: function (e) {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
$('#filter_by_metacode ul li').removeClass('toggledOff')
|
||||
$('.showAllMetacodes').addClass('active')
|
||||
$('.hideAllMetacodes').removeClass('active')
|
||||
|
@ -245,7 +248,7 @@ Metamaps.Filter = {
|
|||
self.passFilters()
|
||||
},
|
||||
filterAllMappers: function (e) {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
$('#filter_by_mapper ul li').addClass('toggledOff')
|
||||
$('.showAllMappers').removeClass('active')
|
||||
$('.hideAllMappers').addClass('active')
|
||||
|
@ -253,7 +256,7 @@ Metamaps.Filter = {
|
|||
self.passFilters()
|
||||
},
|
||||
filterNoMappers: function (e) {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
$('#filter_by_mapper ul li').removeClass('toggledOff')
|
||||
$('.showAllMappers').addClass('active')
|
||||
$('.hideAllMappers').removeClass('active')
|
||||
|
@ -261,7 +264,7 @@ Metamaps.Filter = {
|
|||
self.passFilters()
|
||||
},
|
||||
filterAllSynapses: function (e) {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
$('#filter_by_synapse ul li').addClass('toggledOff')
|
||||
$('.showAllSynapses').removeClass('active')
|
||||
$('.hideAllSynapses').addClass('active')
|
||||
|
@ -269,7 +272,7 @@ Metamaps.Filter = {
|
|||
self.passFilters()
|
||||
},
|
||||
filterNoSynapses: function (e) {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
$('#filter_by_synapse ul li').removeClass('toggledOff')
|
||||
$('.showAllSynapses').addClass('active')
|
||||
$('.hideAllSynapses').removeClass('active')
|
||||
|
@ -280,7 +283,7 @@ Metamaps.Filter = {
|
|||
// to reduce code redundancy
|
||||
// gets called in the context of a list item in a filter box
|
||||
toggleLi: function (whichToFilter) {
|
||||
var self = Metamaps.Filter, index
|
||||
var self = Filter, index
|
||||
var id = $(this).attr('data-id')
|
||||
if (self.visible[whichToFilter].indexOf(id) == -1) {
|
||||
self.visible[whichToFilter].push(id)
|
||||
|
@ -293,7 +296,7 @@ Metamaps.Filter = {
|
|||
self.passFilters()
|
||||
},
|
||||
toggleMetacode: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
self.toggleLi.call(this, 'metacodes')
|
||||
|
||||
if (self.visible.metacodes.length === self.filters.metacodes.length) {
|
||||
|
@ -309,7 +312,7 @@ Metamaps.Filter = {
|
|||
}
|
||||
},
|
||||
toggleMapper: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
self.toggleLi.call(this, 'mappers')
|
||||
|
||||
if (self.visible.mappers.length === self.filters.mappers.length) {
|
||||
|
@ -325,7 +328,7 @@ Metamaps.Filter = {
|
|||
}
|
||||
},
|
||||
toggleSynapse: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
self.toggleLi.call(this, 'synapses')
|
||||
|
||||
if (self.visible.synapses.length === self.filters.synapses.length) {
|
||||
|
@ -341,16 +344,16 @@ Metamaps.Filter = {
|
|||
}
|
||||
},
|
||||
passFilters: function () {
|
||||
var self = Metamaps.Filter
|
||||
var self = Filter
|
||||
var visible = self.visible
|
||||
|
||||
var passesMetacode, passesMapper, passesSynapse
|
||||
var onMap
|
||||
|
||||
if (Metamaps.Active.Map) {
|
||||
if (Active.Map) {
|
||||
onMap = true
|
||||
}
|
||||
else if (Metamaps.Active.Topic) {
|
||||
else if (Active.Topic) {
|
||||
onMap = false
|
||||
}
|
||||
|
||||
|
@ -386,10 +389,10 @@ Metamaps.Filter = {
|
|||
else console.log(topic)
|
||||
} else {
|
||||
if (n) {
|
||||
Metamaps.Control.deselectNode(n, true)
|
||||
Control.deselectNode(n, true)
|
||||
n.setData('alpha', opacityForFilter, 'end')
|
||||
n.eachAdjacency(function (e) {
|
||||
Metamaps.Control.deselectEdge(e, true)
|
||||
Control.deselectEdge(e, true)
|
||||
})
|
||||
}
|
||||
else console.log(topic)
|
||||
|
@ -442,12 +445,12 @@ Metamaps.Filter = {
|
|||
if (visible.mappers.indexOf(user_id) == -1) passesMapper = false
|
||||
else passesMapper = true
|
||||
|
||||
var color = Metamaps.Settings.colors.synapses.normal
|
||||
var color = Settings.colors.synapses.normal
|
||||
if (passesSynapse && passesMapper) {
|
||||
e.setData('alpha', 1, 'end')
|
||||
e.setData('color', color, 'end')
|
||||
} else {
|
||||
Metamaps.Control.deselectEdge(e, true)
|
||||
Control.deselectEdge(e, true)
|
||||
e.setData('alpha', opacityForFilter, 'end')
|
||||
}
|
||||
|
||||
|
@ -457,10 +460,12 @@ Metamaps.Filter = {
|
|||
})
|
||||
|
||||
// run the animation
|
||||
Metamaps.Visualize.mGraph.fx.animate({
|
||||
Visualize.mGraph.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'],
|
||||
duration: 200
|
||||
})
|
||||
}
|
||||
}; // end Metamaps.Filter
|
||||
}
|
||||
|
||||
export default Filter
|
646
frontend/src/Metamaps/GlobalUI.js
Normal file
646
frontend/src/Metamaps/GlobalUI.js
Normal file
|
@ -0,0 +1,646 @@
|
|||
import Active from './Active'
|
||||
import Create from './Create'
|
||||
import Filter from './Filter'
|
||||
import Router from './Router'
|
||||
|
||||
/*
|
||||
* Metamaps.Backbone
|
||||
* Metamaps.Erb
|
||||
* Metamaps.Maps
|
||||
*/
|
||||
|
||||
const GlobalUI = {
|
||||
notifyTimeout: null,
|
||||
lightbox: null,
|
||||
init: function () {
|
||||
var self = GlobalUI;
|
||||
|
||||
self.Search.init();
|
||||
self.CreateMap.init();
|
||||
self.Account.init();
|
||||
|
||||
if ($('#toast').html().trim()) self.notifyUser($('#toast').html())
|
||||
|
||||
//bind lightbox clicks
|
||||
$('.openLightbox').click(function (event) {
|
||||
self.openLightbox($(this).attr('data-open'));
|
||||
event.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#lightbox_screen, #lightbox_close').click(self.closeLightbox);
|
||||
|
||||
// initialize global backbone models and collections
|
||||
if (Active.Mapper) Active.Mapper = new Metamaps.Backbone.Mapper(Active.Mapper);
|
||||
|
||||
var myCollection = Metamaps.Maps.Mine ? Metamaps.Maps.Mine : [];
|
||||
var sharedCollection = Metamaps.Maps.Shared ? Metamaps.Maps.Shared : [];
|
||||
var starredCollection = Metamaps.Maps.Starred ? Metamaps.Maps.Starred : [];
|
||||
var mapperCollection = [];
|
||||
var mapperOptionsObj = {id: 'mapper', sortBy: 'updated_at' };
|
||||
if (Metamaps.Maps.Mapper) {
|
||||
mapperCollection = Metamaps.Maps.Mapper.models;
|
||||
mapperOptionsObj.mapperId = Metamaps.Maps.Mapper.id;
|
||||
}
|
||||
var featuredCollection = Metamaps.Maps.Featured ? Metamaps.Maps.Featured : [];
|
||||
var activeCollection = Metamaps.Maps.Active ? Metamaps.Maps.Active : [];
|
||||
Metamaps.Maps.Mine = new Metamaps.Backbone.MapsCollection(myCollection, {id: 'mine', sortBy: 'updated_at' });
|
||||
Metamaps.Maps.Shared = new Metamaps.Backbone.MapsCollection(sharedCollection, {id: 'shared', sortBy: 'updated_at' });
|
||||
Metamaps.Maps.Starred = new Metamaps.Backbone.MapsCollection(starredCollection, {id: 'starred', sortBy: 'updated_at' });
|
||||
// 'Mapper' refers to another mapper
|
||||
Metamaps.Maps.Mapper = new Metamaps.Backbone.MapsCollection(mapperCollection, mapperOptionsObj);
|
||||
Metamaps.Maps.Featured = new Metamaps.Backbone.MapsCollection(featuredCollection, {id: 'featured', sortBy: 'updated_at' });
|
||||
Metamaps.Maps.Active = new Metamaps.Backbone.MapsCollection(activeCollection, {id: 'active', sortBy: 'updated_at' });
|
||||
},
|
||||
showDiv: function (selector) {
|
||||
$(selector).show()
|
||||
$(selector).animate({
|
||||
opacity: 1
|
||||
}, 200, 'easeOutCubic')
|
||||
},
|
||||
hideDiv: function (selector) {
|
||||
$(selector).animate({
|
||||
opacity: 0
|
||||
}, 200, 'easeInCubic', function () { $(this).hide() })
|
||||
},
|
||||
openLightbox: function (which) {
|
||||
var self = GlobalUI;
|
||||
|
||||
$('.lightboxContent').hide();
|
||||
$('#' + which).show();
|
||||
|
||||
self.lightbox = which;
|
||||
|
||||
$('#lightbox_overlay').show();
|
||||
|
||||
var heightOfContent = '-' + ($('#lightbox_main').height() / 2) + 'px';
|
||||
// animate the content in from the bottom
|
||||
$('#lightbox_main').animate({
|
||||
'top': '50%',
|
||||
'margin-top': heightOfContent
|
||||
}, 200, 'easeOutCubic');
|
||||
|
||||
// fade the black overlay in
|
||||
$('#lightbox_screen').animate({
|
||||
'opacity': '0.42'
|
||||
}, 200);
|
||||
|
||||
if (which == "switchMetacodes") {
|
||||
Create.isSwitchingSet = true;
|
||||
}
|
||||
},
|
||||
|
||||
closeLightbox: function (event) {
|
||||
var self = GlobalUI;
|
||||
|
||||
if (event) event.preventDefault();
|
||||
|
||||
// animate the lightbox content offscreen
|
||||
$('#lightbox_main').animate({
|
||||
'top': '100%',
|
||||
'margin-top': '0'
|
||||
}, 200, 'easeInCubic');
|
||||
|
||||
// fade the black overlay out
|
||||
$('#lightbox_screen').animate({
|
||||
'opacity': '0.0'
|
||||
}, 200, function () {
|
||||
$('#lightbox_overlay').hide();
|
||||
});
|
||||
|
||||
if (self.lightbox === 'forkmap') GlobalUI.CreateMap.reset('fork_map');
|
||||
if (self.lightbox === 'newmap') GlobalUI.CreateMap.reset('new_map');
|
||||
if (Create && Create.isSwitchingSet) {
|
||||
Create.cancelMetacodeSetSwitch();
|
||||
}
|
||||
self.lightbox = null;
|
||||
},
|
||||
notifyUser: function (message, leaveOpen) {
|
||||
var self = GlobalUI;
|
||||
|
||||
$('#toast').html(message)
|
||||
self.showDiv('#toast')
|
||||
clearTimeout(self.notifyTimeOut);
|
||||
if (!leaveOpen) {
|
||||
self.notifyTimeOut = setTimeout(function () {
|
||||
self.hideDiv('#toast')
|
||||
}, 8000);
|
||||
}
|
||||
},
|
||||
clearNotify: function() {
|
||||
var self = GlobalUI;
|
||||
|
||||
clearTimeout(self.notifyTimeOut);
|
||||
self.hideDiv('#toast')
|
||||
},
|
||||
shareInvite: function(inviteLink) {
|
||||
window.prompt("To copy the invite link, press: Ctrl+C, Enter", inviteLink);
|
||||
}
|
||||
}
|
||||
|
||||
GlobalUI.CreateMap = {
|
||||
newMap: null,
|
||||
emptyMapForm: "",
|
||||
emptyForkMapForm: "",
|
||||
topicsToMap: [],
|
||||
synapsesToMap: [],
|
||||
init: function () {
|
||||
var self = GlobalUI.CreateMap;
|
||||
|
||||
self.newMap = new Metamaps.Backbone.Map({ permission: 'commons' });
|
||||
|
||||
self.bindFormEvents();
|
||||
|
||||
self.emptyMapForm = $('#new_map').html();
|
||||
|
||||
},
|
||||
bindFormEvents: function () {
|
||||
var self = GlobalUI.CreateMap;
|
||||
|
||||
$('.new_map input, .new_map div').unbind('keypress').bind('keypress', function(event) {
|
||||
if (event.keyCode === 13) self.submit()
|
||||
})
|
||||
|
||||
$('.new_map button.cancel').unbind().bind('click', function (event) {
|
||||
event.preventDefault();
|
||||
GlobalUI.closeLightbox();
|
||||
});
|
||||
$('.new_map button.submitMap').unbind().bind('click', self.submit);
|
||||
|
||||
// bind permission changer events on the createMap form
|
||||
$('.permIcon').unbind().bind('click', self.switchPermission);
|
||||
},
|
||||
closeSuccess: function () {
|
||||
$('#mapCreatedSuccess').fadeOut(300, function(){
|
||||
$(this).remove();
|
||||
});
|
||||
},
|
||||
generateSuccessMessage: function (id) {
|
||||
var stringStart = "<div id='mapCreatedSuccess'><h6>SUCCESS!</h6>Your map has been created. Do you want to: <a id='mapGo' href='/maps/";
|
||||
stringStart += id;
|
||||
stringStart += "' onclick='GlobalUI.CreateMap.closeSuccess();'>Go to your new map</a>";
|
||||
stringStart += "<span>OR</span><a id='mapStay' href='#' onclick='GlobalUI.CreateMap.closeSuccess(); return false;'>Stay on this ";
|
||||
var page = Active.Map ? 'map' : 'page';
|
||||
var stringEnd = "</a></div>";
|
||||
return stringStart + page + stringEnd;
|
||||
},
|
||||
switchPermission: function () {
|
||||
var self = GlobalUI.CreateMap;
|
||||
|
||||
self.newMap.set('permission', $(this).attr('data-permission'));
|
||||
$(this).siblings('.permIcon').find('.mapPermIcon').removeClass('selected');
|
||||
$(this).find('.mapPermIcon').addClass('selected');
|
||||
|
||||
var permText = $(this).find('.tip').html();
|
||||
$(this).parents('.new_map').find('.permText').html(permText);
|
||||
},
|
||||
submit: function (event) {
|
||||
if (event) event.preventDefault();
|
||||
|
||||
var self = GlobalUI.CreateMap;
|
||||
|
||||
if (GlobalUI.lightbox === 'forkmap') {
|
||||
self.newMap.set('topicsToMap', self.topicsToMap);
|
||||
self.newMap.set('synapsesToMap', self.synapsesToMap);
|
||||
}
|
||||
|
||||
var formId = GlobalUI.lightbox === 'forkmap' ? '#fork_map' : '#new_map';
|
||||
var $form = $(formId);
|
||||
|
||||
self.newMap.set('name', $form.find('#map_name').val());
|
||||
self.newMap.set('desc', $form.find('#map_desc').val());
|
||||
|
||||
if (self.newMap.get('name').length===0){
|
||||
self.throwMapNameError();
|
||||
return;
|
||||
}
|
||||
|
||||
self.newMap.save(null, {
|
||||
success: self.success
|
||||
// TODO add error message
|
||||
});
|
||||
|
||||
GlobalUI.closeLightbox();
|
||||
GlobalUI.notifyUser('Working...');
|
||||
},
|
||||
throwMapNameError: function () {
|
||||
var self = GlobalUI.CreateMap;
|
||||
|
||||
var formId = GlobalUI.lightbox === 'forkmap' ? '#fork_map' : '#new_map';
|
||||
var $form = $(formId);
|
||||
|
||||
var message = $("<div class='feedback_message'>Please enter a map name...</div>");
|
||||
|
||||
$form.find('#map_name').after(message);
|
||||
setTimeout(function(){
|
||||
message.fadeOut('fast', function(){
|
||||
message.remove();
|
||||
});
|
||||
}, 5000);
|
||||
},
|
||||
success: function (model) {
|
||||
var self = GlobalUI.CreateMap;
|
||||
|
||||
//push the new map onto the collection of 'my maps'
|
||||
Metamaps.Maps.Mine.add(model);
|
||||
|
||||
var formId = GlobalUI.lightbox === 'forkmap' ? '#fork_map' : '#new_map';
|
||||
var form = $(formId);
|
||||
|
||||
GlobalUI.clearNotify();
|
||||
$('#wrapper').append(self.generateSuccessMessage(model.id));
|
||||
|
||||
},
|
||||
reset: function (id) {
|
||||
var self = GlobalUI.CreateMap;
|
||||
|
||||
var form = $('#' + id);
|
||||
|
||||
if (id === "fork_map") {
|
||||
self.topicsToMap = [];
|
||||
self.synapsesToMap = [];
|
||||
form.html(self.emptyForkMapForm);
|
||||
}
|
||||
else {
|
||||
form.html(self.emptyMapForm);
|
||||
}
|
||||
|
||||
self.bindFormEvents();
|
||||
self.newMap = new Metamaps.Backbone.Map({ permission: 'commons' });
|
||||
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
GlobalUI.Account = {
|
||||
isOpen: false,
|
||||
changing: false,
|
||||
init: function () {
|
||||
var self = GlobalUI.Account;
|
||||
|
||||
$('.sidebarAccountIcon').click(self.toggleBox);
|
||||
$('.sidebarAccountBox').click(function(event){
|
||||
event.stopPropagation();
|
||||
});
|
||||
$('body').click(self.close);
|
||||
},
|
||||
toggleBox: function (event) {
|
||||
var self = GlobalUI.Account;
|
||||
|
||||
if (self.isOpen) self.close();
|
||||
else self.open();
|
||||
|
||||
event.stopPropagation();
|
||||
},
|
||||
open: function () {
|
||||
var self = GlobalUI.Account;
|
||||
|
||||
Filter.close();
|
||||
$('.sidebarAccountIcon .tooltipsUnder').addClass('hide');
|
||||
|
||||
|
||||
if (!self.isOpen && !self.changing) {
|
||||
self.changing = true;
|
||||
$('.sidebarAccountBox').fadeIn(200, function () {
|
||||
self.changing = false;
|
||||
self.isOpen = true;
|
||||
$('.sidebarAccountBox #user_email').focus();
|
||||
});
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
var self = GlobalUI.Account;
|
||||
|
||||
$('.sidebarAccountIcon .tooltipsUnder').removeClass('hide');
|
||||
if (!self.changing) {
|
||||
self.changing = true;
|
||||
$('.sidebarAccountBox #user_email').blur();
|
||||
$('.sidebarAccountBox').fadeOut(200, function () {
|
||||
self.changing = false;
|
||||
self.isOpen = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GlobalUI.Search = {
|
||||
locked: false,
|
||||
isOpen: false,
|
||||
limitTopicsToMe: false,
|
||||
limitMapsToMe: false,
|
||||
timeOut: null,
|
||||
changing: false,
|
||||
optionsInitialized: false,
|
||||
init: function () {
|
||||
var self = GlobalUI.Search;
|
||||
|
||||
var loader = new CanvasLoader('searchLoading');
|
||||
loader.setColor('#4fb5c0'); // default is '#000000'
|
||||
loader.setDiameter(24); // default is 40
|
||||
loader.setDensity(41); // default is 40
|
||||
loader.setRange(0.9); // default is 1.3
|
||||
loader.show(); // Hidden by default
|
||||
|
||||
// bind the hover events
|
||||
$(".sidebarSearch").hover(function () {
|
||||
self.open()
|
||||
}, function () {
|
||||
self.close(800, false)
|
||||
});
|
||||
|
||||
$('.sidebarSearchIcon').click(function (e) {
|
||||
$('.sidebarSearchField').focus();
|
||||
});
|
||||
$('.sidebarSearch').click(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
$('body').click(function (e) {
|
||||
self.close(0, false);
|
||||
});
|
||||
|
||||
// open if the search is closed and user hits ctrl+/
|
||||
// close if they hit ESC
|
||||
$('body').bind('keyup', function (e) {
|
||||
switch (e.which) {
|
||||
case 191:
|
||||
if ((e.ctrlKey && !self.isOpen) || (e.ctrlKey && self.locked)) {
|
||||
self.open(true); // true for focus
|
||||
}
|
||||
break;
|
||||
case 27:
|
||||
if (self.isOpen) {
|
||||
self.close(0, true);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break; //console.log(e.which);
|
||||
}
|
||||
});
|
||||
|
||||
self.startTypeahead();
|
||||
},
|
||||
lock: function() {
|
||||
var self = GlobalUI.Search;
|
||||
self.locked = true;
|
||||
},
|
||||
unlock: function() {
|
||||
var self = GlobalUI.Search;
|
||||
self.locked = false;
|
||||
},
|
||||
open: function (focus) {
|
||||
var self = GlobalUI.Search;
|
||||
|
||||
clearTimeout(self.timeOut);
|
||||
if (!self.isOpen && !self.changing && !self.locked) {
|
||||
self.changing = true;
|
||||
$('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({
|
||||
width: '400px'
|
||||
}, 300, function () {
|
||||
if (focus) $('.sidebarSearchField').focus();
|
||||
$('.sidebarSearchField, .sidebarSearch .tt-hint').css({
|
||||
padding: '7px 10px 3px 10px',
|
||||
width: '380px'
|
||||
});
|
||||
self.changing = false;
|
||||
self.isOpen = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
close: function (closeAfter, bypass) {
|
||||
// for now
|
||||
return
|
||||
|
||||
var self = GlobalUI.Search;
|
||||
|
||||
self.timeOut = setTimeout(function () {
|
||||
if (!self.locked && !self.changing && self.isOpen && (bypass || $('.sidebarSearchField.tt-input').val() == '')) {
|
||||
self.changing = true;
|
||||
$('.sidebarSearchField, .sidebarSearch .tt-hint').css({
|
||||
padding: '7px 0 3px 0',
|
||||
width: '400px'
|
||||
});
|
||||
$('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({
|
||||
width: '0'
|
||||
}, 300, function () {
|
||||
$('.sidebarSearchField').typeahead('val', '');
|
||||
$('.sidebarSearchField').blur();
|
||||
self.changing = false;
|
||||
self.isOpen = false;
|
||||
});
|
||||
}
|
||||
}, closeAfter);
|
||||
},
|
||||
startTypeahead: function () {
|
||||
var self = GlobalUI.Search;
|
||||
|
||||
var mapheader = Active.Mapper ? '<div class="searchMapsHeader searchHeader"><h3 class="search-heading">Maps</h3><input type="checkbox" class="limitToMe" id="limitMapsToMe"></input><label for="limitMapsToMe" class="limitToMeLabel">added by me</label><div class="minimizeResults minimizeMapResults"></div><div class="clearfloat"></div></div>' : '<div class="searchMapsHeader searchHeader"><h3 class="search-heading">Maps</h3><div class="minimizeResults minimizeMapResults"></div><div class="clearfloat"></div></div>';
|
||||
var topicheader = Active.Mapper ? '<div class="searchTopicsHeader searchHeader"><h3 class="search-heading">Topics</h3><input type="checkbox" class="limitToMe" id="limitTopicsToMe"></input><label for="limitTopicsToMe" class="limitToMeLabel">added by me</label><div class="minimizeResults minimizeTopicResults"></div><div class="clearfloat"></div></div>' : '<div class="searchTopicsHeader searchHeader"><h3 class="search-heading">Topics</h3><div class="minimizeResults minimizeTopicResults"></div><div class="clearfloat"></div></div>';
|
||||
var mapperheader = '<div class="searchMappersHeader searchHeader"><h3 class="search-heading">Mappers</h3><div class="minimizeResults minimizeMapperResults"></div><div class="clearfloat"></div></div>';
|
||||
|
||||
var topics = {
|
||||
name: 'topics',
|
||||
limit: 9999,
|
||||
|
||||
display: function(s) { return s.label; },
|
||||
templates: {
|
||||
notFound: function(s) {
|
||||
return Hogan.compile(topicheader + $('#topicSearchTemplate').html()).render({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
typeImageURL: Metamaps.Erb['icons/wildcard.png'],
|
||||
rtype: "noresult"
|
||||
});
|
||||
},
|
||||
header: topicheader,
|
||||
suggestion: function(s) {
|
||||
return Hogan.compile($('#topicSearchTemplate').html()).render(s);
|
||||
},
|
||||
},
|
||||
source: new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: '/search/topics',
|
||||
prepare: function(query, settings) {
|
||||
settings.url += '?term=' + query;
|
||||
if (Active.Mapper && self.limitTopicsToMe) {
|
||||
settings.url += "&user=" + Active.Mapper.id.toString();
|
||||
}
|
||||
return settings;
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
var maps = {
|
||||
name: 'maps',
|
||||
limit: 9999,
|
||||
display: function(s) { return s.label; },
|
||||
templates: {
|
||||
notFound: function(s) {
|
||||
return Hogan.compile(mapheader + $('#mapSearchTemplate').html()).render({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
rtype: "noresult"
|
||||
});
|
||||
},
|
||||
header: mapheader,
|
||||
suggestion: function(s) {
|
||||
return Hogan.compile($('#mapSearchTemplate').html()).render(s);
|
||||
},
|
||||
},
|
||||
source: new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: '/search/maps',
|
||||
prepare: function(query, settings) {
|
||||
settings.url += '?term=' + query;
|
||||
if (Active.Mapper && self.limitMapsToMe) {
|
||||
settings.url += "&user=" + Active.Mapper.id.toString();
|
||||
}
|
||||
return settings;
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
var mappers = {
|
||||
name: 'mappers',
|
||||
limit: 9999,
|
||||
display: function(s) { return s.label; },
|
||||
templates: {
|
||||
notFound: function(s) {
|
||||
return Hogan.compile(mapperheader + $('#mapperSearchTemplate').html()).render({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
rtype: "noresult",
|
||||
profile: Metamaps.Erb['user.png']
|
||||
});
|
||||
},
|
||||
header: mapperheader,
|
||||
suggestion: function(s) {
|
||||
return Hogan.compile($('#mapperSearchTemplate').html()).render(s);
|
||||
},
|
||||
},
|
||||
source: new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: '/search/mappers?term=%QUERY',
|
||||
wildcard: '%QUERY',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
// Take all that crazy setup data and put it together into one beautiful typeahead call!
|
||||
$('.sidebarSearchField').typeahead(
|
||||
{
|
||||
highlight: true,
|
||||
},
|
||||
[topics, maps, mappers]
|
||||
);
|
||||
|
||||
//Set max height of the search results box to prevent it from covering bottom left footer
|
||||
$('.sidebarSearchField').bind('typeahead:render', function (event) {
|
||||
self.initSearchOptions();
|
||||
self.hideLoader();
|
||||
var h = $(window).height();
|
||||
$(".tt-dropdown-menu").css('max-height', h - 100);
|
||||
if (self.limitTopicsToMe) {
|
||||
$('#limitTopicsToMe').prop('checked', true);
|
||||
}
|
||||
if (self.limitMapsToMe) {
|
||||
$('#limitMapsToMe').prop('checked', true);
|
||||
}
|
||||
});
|
||||
$(window).resize(function () {
|
||||
var h = $(window).height();
|
||||
$(".tt-dropdown-menu").css('max-height', h - 100);
|
||||
});
|
||||
|
||||
// tell the autocomplete to launch a new tab with the topic, map, or mapper you clicked on
|
||||
$('.sidebarSearchField').bind('typeahead:select', self.handleResultClick);
|
||||
|
||||
// don't do it, if they clicked on a 'addToMap' button
|
||||
$('.sidebarSearch button.addToMap').click(function (event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// make sure that when you click on 'limit to me' or 'toggle section' it works
|
||||
$('.sidebarSearchField.tt-input').keyup(function(){
|
||||
if ($('.sidebarSearchField.tt-input').val() === '') {
|
||||
self.hideLoader();
|
||||
} else {
|
||||
self.showLoader();
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
handleResultClick: function (event, datum, dataset) {
|
||||
var self = GlobalUI.Search;
|
||||
|
||||
self.hideLoader();
|
||||
|
||||
if (["topic", "map", "mapper"].indexOf(datum.rtype) !== -1) {
|
||||
self.close(0, true);
|
||||
var win;
|
||||
if (datum.rtype == "topic") {
|
||||
Router.topics(datum.id);
|
||||
} else if (datum.rtype == "map") {
|
||||
Router.maps(datum.id);
|
||||
} else if (datum.rtype == "mapper") {
|
||||
Router.explore("mapper", datum.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
initSearchOptions: function () {
|
||||
var self = GlobalUI.Search;
|
||||
|
||||
function toggleResultSet(set) {
|
||||
var s = $('.tt-dataset-' + set + ' .tt-suggestion, .tt-dataset-' + set + ' .resultnoresult');
|
||||
if (s.is(':visible')) {
|
||||
s.hide();
|
||||
$(this).removeClass('minimizeResults').addClass('maximizeResults');
|
||||
} else {
|
||||
s.show();
|
||||
$(this).removeClass('maximizeResults').addClass('minimizeResults');
|
||||
}
|
||||
}
|
||||
|
||||
$('.limitToMe').unbind().bind("change", function (e) {
|
||||
if ($(this).attr('id') == 'limitTopicsToMe') {
|
||||
self.limitTopicsToMe = !self.limitTopicsToMe;
|
||||
}
|
||||
if ($(this).attr('id') == 'limitMapsToMe') {
|
||||
self.limitMapsToMe = !self.limitMapsToMe;
|
||||
}
|
||||
|
||||
// set the value of the search equal to itself to retrigger the
|
||||
// autocomplete event
|
||||
var searchQuery = $('.sidebarSearchField.tt-input').val();
|
||||
$(".sidebarSearchField").typeahead('val', '')
|
||||
.typeahead('val', searchQuery);
|
||||
});
|
||||
|
||||
// when the user clicks minimize section, hide the results for that section
|
||||
$('.minimizeMapperResults').unbind().click(function (e) {
|
||||
toggleResultSet.call(this, 'mappers');
|
||||
});
|
||||
$('.minimizeTopicResults').unbind().click(function (e) {
|
||||
toggleResultSet.call(this, 'topics');
|
||||
});
|
||||
$('.minimizeMapResults').unbind().click(function (e) {
|
||||
toggleResultSet.call(this, 'maps');
|
||||
});
|
||||
},
|
||||
hideLoader: function () {
|
||||
$('#searchLoading').hide();
|
||||
},
|
||||
showLoader: function () {
|
||||
$('#searchLoading').show();
|
||||
}
|
||||
}
|
||||
|
||||
export default GlobalUI
|
|
@ -1,19 +1,23 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import Active from './Active'
|
||||
import GlobalUI from './GlobalUI'
|
||||
import Map from './Map'
|
||||
import Synapse from './Synapse'
|
||||
import Topic from './Topic'
|
||||
|
||||
/*
|
||||
* Metamaps.Import.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.Backbone
|
||||
* - Metamaps.Map
|
||||
* - Metamaps.Mappings
|
||||
* - Metamaps.Metacodes
|
||||
* - Metamaps.Synapses
|
||||
* - Metamaps.Topics
|
||||
*/
|
||||
|
||||
Metamaps.Import = {
|
||||
const Import = {
|
||||
// note that user is not imported
|
||||
topicWhitelist: [
|
||||
'id', 'name', 'metacode', 'x', 'y', 'description', 'link', 'permission'
|
||||
|
@ -24,19 +28,19 @@ Metamaps.Import = {
|
|||
cidMappings: {}, // to be filled by import_id => cid mappings
|
||||
|
||||
handleTSV: function (text) {
|
||||
var self = Metamaps.Import
|
||||
var self = Import
|
||||
results = self.parseTabbedString(text)
|
||||
self.handle(results)
|
||||
},
|
||||
|
||||
handleJSON: function (text) {
|
||||
var self = Metamaps.Import
|
||||
var self = Import
|
||||
results = JSON.parse(text)
|
||||
self.handle(results)
|
||||
},
|
||||
|
||||
handle: function(results) {
|
||||
var self = Metamaps.Import
|
||||
var self = Import
|
||||
var topics = results.topics
|
||||
var synapses = results.synapses
|
||||
|
||||
|
@ -60,7 +64,7 @@ Metamaps.Import = {
|
|||
},
|
||||
|
||||
parseTabbedString: function (text) {
|
||||
var self = Metamaps.Import
|
||||
var self = Import
|
||||
|
||||
// determine line ending and split lines
|
||||
var delim = '\n'
|
||||
|
@ -186,7 +190,7 @@ Metamaps.Import = {
|
|||
},
|
||||
|
||||
importTopics: function (parsedTopics) {
|
||||
var self = Metamaps.Import
|
||||
var self = Import
|
||||
|
||||
// up to 25 topics: scale 100
|
||||
// up to 81 topics: scale 200
|
||||
|
@ -219,7 +223,7 @@ Metamaps.Import = {
|
|||
},
|
||||
|
||||
importSynapses: function (parsedSynapses) {
|
||||
var self = Metamaps.Import
|
||||
var self = Import
|
||||
|
||||
parsedSynapses.forEach(function (synapse) {
|
||||
// only createSynapseWithParameters once both topics are persisted
|
||||
|
@ -255,16 +259,16 @@ Metamaps.Import = {
|
|||
|
||||
createTopicWithParameters: function (name, metacode_name, permission, desc,
|
||||
link, xloc, yloc, import_id, opts) {
|
||||
var self = Metamaps.Import
|
||||
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
|
||||
var self = Import
|
||||
$(document).trigger(Map.events.editedByActiveMapper)
|
||||
var metacode = Metamaps.Metacodes.where({name: metacode_name})[0] || null
|
||||
if (metacode === null) {
|
||||
metacode = Metamaps.Metacodes.where({ name: 'Wildcard' })[0]
|
||||
console.warn("Couldn't find metacode " + metacode_name + ' so used Wildcard instead.')
|
||||
}
|
||||
|
||||
var topic_permission = permission || Metamaps.Active.Map.get('permission')
|
||||
var defer_to_map_id = permission === topic_permission ? Metamaps.Active.Map.get('id') : null
|
||||
var topic_permission = permission || Active.Map.get('permission')
|
||||
var defer_to_map_id = permission === topic_permission ? Active.Map.get('id') : null
|
||||
var topic = new Metamaps.Backbone.Topic({
|
||||
name: name,
|
||||
metacode_id: metacode.id,
|
||||
|
@ -272,7 +276,7 @@ Metamaps.Import = {
|
|||
defer_to_map_id: defer_to_map_id,
|
||||
desc: desc || "",
|
||||
link: link || "",
|
||||
calculated_permission: Metamaps.Active.Map.get('permission')
|
||||
calculated_permission: Active.Map.get('permission')
|
||||
})
|
||||
Metamaps.Topics.add(topic)
|
||||
|
||||
|
@ -289,11 +293,11 @@ Metamaps.Import = {
|
|||
Metamaps.Mappings.add(mapping)
|
||||
|
||||
// this function also includes the creation of the topic in the database
|
||||
Metamaps.Topic.renderTopic(mapping, topic, true, true, {
|
||||
Topic.renderTopic(mapping, topic, true, true, {
|
||||
success: opts.success
|
||||
})
|
||||
|
||||
Metamaps.GlobalUI.hideDiv('#instructions')
|
||||
GlobalUI.hideDiv('#instructions')
|
||||
},
|
||||
|
||||
createSynapseWithParameters: function (desc, category, permission,
|
||||
|
@ -321,6 +325,8 @@ Metamaps.Import = {
|
|||
})
|
||||
Metamaps.Mappings.add(mapping)
|
||||
|
||||
Metamaps.Synapse.renderSynapse(mapping, synapse, node1, node2, true)
|
||||
Synapse.renderSynapse(mapping, synapse, node1, node2, true)
|
||||
}
|
||||
}
|
||||
|
||||
export default Import
|
File diff suppressed because it is too large
Load diff
123
frontend/src/Metamaps/Listeners.js
Normal file
123
frontend/src/Metamaps/Listeners.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
/* global $ */
|
||||
|
||||
import Active from './Active'
|
||||
import Control from './Control'
|
||||
import JIT from './JIT'
|
||||
import Mobile from './Mobile'
|
||||
import Realtime from './Realtime'
|
||||
import Selected from './Selected'
|
||||
import Topic from './Topic'
|
||||
import Visualize from './Visualize'
|
||||
|
||||
const Listeners = {
|
||||
init: function () {
|
||||
var self = this
|
||||
$(document).on('keydown', function (e) {
|
||||
if (!(Active.Map || Active.Topic)) return
|
||||
|
||||
switch (e.which) {
|
||||
case 13: // if enter key is pressed
|
||||
JIT.enterKeyHandler()
|
||||
e.preventDefault()
|
||||
break
|
||||
case 27: // if esc key is pressed
|
||||
JIT.escKeyHandler()
|
||||
break
|
||||
case 65: // if a or A is pressed
|
||||
if (e.ctrlKey) {
|
||||
Control.deselectAllNodes()
|
||||
Control.deselectAllEdges()
|
||||
|
||||
e.preventDefault()
|
||||
Visualize.mGraph.graph.eachNode(function (n) {
|
||||
Control.selectNode(n, e)
|
||||
})
|
||||
|
||||
Visualize.mGraph.plot()
|
||||
}
|
||||
|
||||
break
|
||||
case 68: // if d or D is pressed
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault()
|
||||
Control.deleteSelected()
|
||||
}
|
||||
break
|
||||
case 69: // if e or E is pressed
|
||||
if (e.ctrlKey && Active.Map) {
|
||||
e.preventDefault()
|
||||
JIT.zoomExtents(null, Visualize.mGraph.canvas)
|
||||
break
|
||||
}
|
||||
if (e.altKey && Active.Topic) {
|
||||
e.preventDefault()
|
||||
|
||||
if (Active.Topic) {
|
||||
self.centerAndReveal(Selected.Nodes, {
|
||||
center: true,
|
||||
reveal: false
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
case 72: // if h or H is pressed
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault()
|
||||
Control.hideSelectedNodes()
|
||||
Control.hideSelectedEdges()
|
||||
}
|
||||
break
|
||||
case 77: // if m or M is pressed
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault()
|
||||
Control.removeSelectedNodes()
|
||||
Control.removeSelectedEdges()
|
||||
}
|
||||
break
|
||||
case 82: // if r or R is pressed
|
||||
if (e.altKey && Active.Topic) {
|
||||
e.preventDefault()
|
||||
self.centerAndReveal(Selected.Nodes, {
|
||||
center: false,
|
||||
reveal: true
|
||||
})
|
||||
}
|
||||
break
|
||||
case 84: // if t or T is pressed
|
||||
if (e.altKey && Active.Topic) {
|
||||
e.preventDefault()
|
||||
self.centerAndReveal(Selected.Nodes, {
|
||||
center: true,
|
||||
reveal: true
|
||||
})
|
||||
}
|
||||
break
|
||||
default:
|
||||
// console.log(e.which)
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
$(window).resize(function () {
|
||||
if (Visualize && Visualize.mGraph) Visualize.mGraph.canvas.resize($(window).width(), $(window).height())
|
||||
if (Active.Map && Realtime.inConversation) Realtime.positionVideos()
|
||||
Mobile.resizeTitle()
|
||||
})
|
||||
},
|
||||
centerAndReveal: function(nodes, opts) {
|
||||
if (nodes.length < 1) return
|
||||
var node = nodes[nodes.length - 1]
|
||||
if (opts.center && opts.reveal) {
|
||||
Topic.centerOn(node.id, function() {
|
||||
Topic.fetchRelatives(nodes)
|
||||
})
|
||||
} else if (opts.center) {
|
||||
Topic.centerOn(node.id)
|
||||
} else if (opts.reveal) {
|
||||
Topic.fetchRelatives(nodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Listeners
|
27
frontend/src/Metamaps/Map/CheatSheet.js
Normal file
27
frontend/src/Metamaps/Map/CheatSheet.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
const 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')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default CheatSheet
|
373
frontend/src/Metamaps/Map/InfoBox.js
Normal file
373
frontend/src/Metamaps/Map/InfoBox.js
Normal file
|
@ -0,0 +1,373 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import Active from '../Active'
|
||||
import GlobalUI from '../GlobalUI'
|
||||
import Router from '../Router'
|
||||
import Util from '../Util'
|
||||
|
||||
/*
|
||||
* Metamaps.Collaborators
|
||||
* Metamaps.Erb
|
||||
* Metamaps.Mappers
|
||||
* Metamaps.Maps
|
||||
* Metamaps.Synapses
|
||||
* Metamaps.Topics
|
||||
*/
|
||||
|
||||
const InfoBox = {
|
||||
isOpen: false,
|
||||
changing: 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>",
|
||||
nameHTML: '<span class="best_in_place best_in_place_name" id="best_in_place_map_{{id}}_name" data-url="/maps/{{id}}" data-object="map" data-attribute="name" data-type="textarea" data-activator="#mapInfoName">{{name}}</span>',
|
||||
descHTML: '<span class="best_in_place best_in_place_desc" id="best_in_place_map_{{id}}_desc" data-url="/maps/{{id}}" data-object="map" data-attribute="desc" data-nil="Click to add description..." data-type="textarea" data-activator="#mapInfoDesc">{{desc}}</span>',
|
||||
init: function () {
|
||||
var self = InfoBox
|
||||
|
||||
$('.mapInfoIcon').click(self.toggleBox)
|
||||
$('.mapInfoBox').click(function (event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
$('body').click(self.close)
|
||||
|
||||
self.attachEventListeners()
|
||||
|
||||
self.generateBoxHTML = Hogan.compile($('#mapInfoBoxTemplate').html())
|
||||
|
||||
var querystring = window.location.search.replace(/^\?/, '')
|
||||
if (querystring == 'new') {
|
||||
self.open()
|
||||
$('.mapInfoBox').addClass('mapRequestTitle')
|
||||
}
|
||||
},
|
||||
toggleBox: function (event) {
|
||||
var self = InfoBox
|
||||
|
||||
if (self.isOpen) self.close()
|
||||
else self.open()
|
||||
|
||||
event.stopPropagation()
|
||||
},
|
||||
open: function () {
|
||||
var self = 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 = 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 = InfoBox
|
||||
|
||||
var map = Active.Map
|
||||
|
||||
var obj = map.pick('permission', 'topic_count', 'synapse_count')
|
||||
|
||||
var isCreator = map.authorizePermissionChange(Active.Mapper)
|
||||
var canEdit = map.authorizeToEdit(Active.Mapper)
|
||||
var relevantPeople = map.get('permission') === 'commons' ? Metamaps.Mappers : Metamaps.Collaborators
|
||||
var shareable = map.get('permission') !== 'private'
|
||||
|
||||
obj['name'] = canEdit ? Hogan.compile(self.nameHTML).render({id: map.id, name: map.get('name')}) : map.get('name')
|
||||
obj['desc'] = canEdit ? Hogan.compile(self.descHTML).render({id: map.id, desc: map.get('desc')}) : map.get('desc')
|
||||
obj['map_creator_tip'] = isCreator ? self.changePermissionText : ''
|
||||
|
||||
obj['contributor_count'] = relevantPeople.length
|
||||
obj['contributors_class'] = relevantPeople.length > 1 ? 'multiple' : ''
|
||||
obj['contributors_class'] += relevantPeople.length === 2 ? ' mTwo' : ''
|
||||
obj['contributor_image'] = relevantPeople.length > 0 ? relevantPeople.models[0].get('image') : Metamaps.Erb['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 = 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('<div class="nameCounter forMap"></div>')
|
||||
|
||||
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()
|
||||
Active.Map.set('name', name)
|
||||
Active.Map.trigger('saved')
|
||||
// mobile menu
|
||||
$('#header_content').html(name)
|
||||
$('.mapInfoBox').removeClass('mapRequestTitle')
|
||||
document.title = name + ' | Metamaps'
|
||||
})
|
||||
|
||||
$('.mapInfoDesc .best_in_place_desc').unbind('ajax:success').bind('ajax:success', function () {
|
||||
var desc = $(this).html()
|
||||
Active.Map.set('desc', desc)
|
||||
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(Router.intercept)
|
||||
|
||||
$('.mapInfoBox').unbind('.hideTip').bind('click.hideTip', function () {
|
||||
$('.mapContributors .tip').hide()
|
||||
})
|
||||
|
||||
self.addTypeahead()
|
||||
},
|
||||
addTypeahead: function () {
|
||||
var self = InfoBox
|
||||
|
||||
if (!Active.Map) return
|
||||
|
||||
// for autocomplete
|
||||
var collaborators = {
|
||||
name: 'collaborators',
|
||||
limit: 9999,
|
||||
display: function(s) { return s.label; },
|
||||
templates: {
|
||||
notFound: function(s) {
|
||||
return Hogan.compile($('#collaboratorSearchTemplate').html()).render({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
rtype: "noresult",
|
||||
profile: Metamaps.Erb['user.png'],
|
||||
});
|
||||
},
|
||||
suggestion: function(s) {
|
||||
return Hogan.compile($('#collaboratorSearchTemplate').html()).render(s);
|
||||
},
|
||||
},
|
||||
source: new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: '/search/mappers?term=%QUERY',
|
||||
wildcard: '%QUERY',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// for adding map collaborators, who will have edit rights
|
||||
if (Active.Mapper && Active.Mapper.id === Active.Map.get('user_id')) {
|
||||
$('.collaboratorSearchField').typeahead(
|
||||
{
|
||||
highlight: false,
|
||||
},
|
||||
[collaborators]
|
||||
)
|
||||
$('.collaboratorSearchField').bind('typeahead:select', self.handleResultClick)
|
||||
$('.mapContributors .removeCollaborator').click(function () {
|
||||
self.removeCollaborator(parseInt($(this).data('id')))
|
||||
})
|
||||
}
|
||||
},
|
||||
removeCollaborator: function (collaboratorId) {
|
||||
var self = InfoBox
|
||||
Metamaps.Collaborators.remove(Metamaps.Collaborators.get(collaboratorId))
|
||||
var mapperIds = Metamaps.Collaborators.models.map(function (mapper) { return mapper.id })
|
||||
$.post('/maps/' + Active.Map.id + '/access', { access: mapperIds })
|
||||
self.updateNumbers()
|
||||
},
|
||||
addCollaborator: function (newCollaboratorId) {
|
||||
var self = InfoBox
|
||||
|
||||
if (Metamaps.Collaborators.get(newCollaboratorId)) {
|
||||
GlobalUI.notifyUser('That user already has access')
|
||||
return
|
||||
}
|
||||
|
||||
function callback(mapper) {
|
||||
Metamaps.Collaborators.add(mapper)
|
||||
var mapperIds = Metamaps.Collaborators.models.map(function (mapper) { return mapper.id })
|
||||
$.post('/maps/' + Active.Map.id + '/access', { access: mapperIds })
|
||||
var name = Metamaps.Collaborators.get(newCollaboratorId).get('name')
|
||||
GlobalUI.notifyUser(name + ' will be notified by email')
|
||||
self.updateNumbers()
|
||||
}
|
||||
|
||||
$.getJSON('/users/' + newCollaboratorId + '.json', callback)
|
||||
},
|
||||
handleResultClick: function (event, item) {
|
||||
var self = InfoBox
|
||||
|
||||
self.addCollaborator(item.id)
|
||||
$('.collaboratorSearchField').typeahead('val', '')
|
||||
},
|
||||
updateNameDescPerm: function (name, desc, perm) {
|
||||
$('.mapInfoBox').removeClass('mapRequestTitle')
|
||||
$('.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 = InfoBox
|
||||
var relevantPeople = Active.Map.get('permission') === 'commons' ? Metamaps.Mappers : Metamaps.Collaborators
|
||||
var activeMapperIsCreator = Active.Mapper && Active.Mapper.id === Active.Map.get('user_id')
|
||||
var string = ''
|
||||
string += '<ul>'
|
||||
|
||||
relevantPeople.each(function (m) {
|
||||
var isCreator = Active.Map.get('user_id') === m.get('id')
|
||||
string += '<li><a href="/explore/mapper/' + m.get('id') + '">' + '<img class="rtUserImage" width="25" height="25" src="' + m.get('image') + '" />' + m.get('name')
|
||||
if (isCreator) string += ' (creator)'
|
||||
string += '</a>'
|
||||
if (activeMapperIsCreator && !isCreator) string += '<span class="removeCollaborator" data-id="' + m.get('id') + '"></span>'
|
||||
string += '</li>'
|
||||
})
|
||||
|
||||
string += '</ul>'
|
||||
|
||||
if (activeMapperIsCreator) {
|
||||
string += '<div class="collabSearchField"><span class="addCollab"></span><input class="collaboratorSearchField" placeholder="Add a collaborator!"></input></div>'
|
||||
}
|
||||
return string
|
||||
},
|
||||
updateNumbers: function () {
|
||||
if (!Active.Map) return
|
||||
|
||||
var self = InfoBox
|
||||
var mapper = Active.Mapper
|
||||
var relevantPeople = Active.Map.get('permission') === 'commons' ? Metamaps.Mappers : Metamaps.Collaborators
|
||||
|
||||
var contributors_class = ''
|
||||
if (relevantPeople.length === 2) contributors_class = 'multiple mTwo'
|
||||
else if (relevantPeople.length > 2) contributors_class = 'multiple'
|
||||
|
||||
var contributors_image = Metamaps.Erb['user.png']
|
||||
if (relevantPeople.length > 0) {
|
||||
// get the first contributor and use their image
|
||||
contributors_image = relevantPeople.models[0].get('image')
|
||||
}
|
||||
$('.mapContributors img').attr('src', contributors_image).removeClass('multiple mTwo').addClass(contributors_class)
|
||||
$('.mapContributors span').text(relevantPeople.length)
|
||||
$('.mapContributors .tip').html(self.createContributorList())
|
||||
self.addTypeahead()
|
||||
$('.mapContributors .tip').unbind().click(function (event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
$('.mapTopics').text(Metamaps.Topics.length)
|
||||
$('.mapSynapses').text(Metamaps.Synapses.length)
|
||||
|
||||
$('.mapEditedAt').html('<span>Last edited: </span>' + Util.nowDateFormatted())
|
||||
},
|
||||
onPermissionClick: function (event) {
|
||||
var self = 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('<ul class="permissionSelect"><li class="public"></li><li class="private"></li></ul>')
|
||||
} else if ($(this).hasClass('public')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="private"></li></ul>')
|
||||
} else if ($(this).hasClass('private')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="public"></li></ul>')
|
||||
}
|
||||
$('.mapPermission .permissionSelect li').click(self.selectPermission)
|
||||
event.stopPropagation()
|
||||
}
|
||||
},
|
||||
hidePermissionSelect: function () {
|
||||
var self = 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 = InfoBox
|
||||
|
||||
self.selectingPermission = false
|
||||
var permission = $(this).attr('class')
|
||||
Active.Map.save({
|
||||
permission: permission
|
||||
})
|
||||
Active.Map.updateMapWrapper()
|
||||
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 = Active.Map
|
||||
var mapper = Active.Mapper
|
||||
var authorized = map.authorizePermissionChange(mapper)
|
||||
|
||||
if (doIt && authorized) {
|
||||
InfoBox.close()
|
||||
Metamaps.Maps.Active.remove(map)
|
||||
Metamaps.Maps.Featured.remove(map)
|
||||
Metamaps.Maps.Mine.remove(map)
|
||||
Metamaps.Maps.Shared.remove(map)
|
||||
map.destroy()
|
||||
Router.home()
|
||||
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?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default InfoBox
|
365
frontend/src/Metamaps/Map/index.js
Normal file
365
frontend/src/Metamaps/Map/index.js
Normal file
|
@ -0,0 +1,365 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import Active from '../Active'
|
||||
import AutoLayout from '../AutoLayout'
|
||||
import Create from '../Create'
|
||||
import Filter from '../Filter'
|
||||
import GlobalUI from '../GlobalUI'
|
||||
import JIT from '../JIT'
|
||||
import Realtime from '../Realtime'
|
||||
import Router from '../Router'
|
||||
import Selected from '../Selected'
|
||||
import SynapseCard from '../SynapseCard'
|
||||
import TopicCard from '../TopicCard'
|
||||
import Visualize from '../Visualize'
|
||||
|
||||
import CheatSheet from './CheatSheet'
|
||||
import InfoBox from './InfoBox'
|
||||
|
||||
/*
|
||||
* Metamaps.Map.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Backbone
|
||||
* - Metamaps.Erb
|
||||
* - Metamaps.Loading
|
||||
* - Metamaps.Mappers
|
||||
* - Metamaps.Mappings
|
||||
* - Metamaps.Maps
|
||||
* - Metamaps.Messages
|
||||
* - Metamaps.Synapses
|
||||
* - Metamaps.Topics
|
||||
*/
|
||||
|
||||
const Map = {
|
||||
events: {
|
||||
editedByActiveMapper: 'Metamaps:Map:events:editedByActiveMapper'
|
||||
},
|
||||
init: function () {
|
||||
var self = 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
|
||||
})
|
||||
|
||||
$('.starMap').click(function () {
|
||||
if ($(this).is('.starred')) self.unstar()
|
||||
else self.star()
|
||||
})
|
||||
|
||||
$('.sidebarFork').click(function () {
|
||||
self.fork()
|
||||
})
|
||||
|
||||
GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html()
|
||||
|
||||
self.updateStar()
|
||||
self.InfoBox.init()
|
||||
CheatSheet.init()
|
||||
|
||||
$(document).on(Map.events.editedByActiveMapper, self.editedByActiveMapper)
|
||||
},
|
||||
launch: function (id) {
|
||||
var bb = Metamaps.Backbone
|
||||
var start = function (data) {
|
||||
Active.Map = new bb.Map(data.map)
|
||||
Metamaps.Mappers = new bb.MapperCollection(data.mappers)
|
||||
Metamaps.Collaborators = new bb.MapperCollection(data.collaborators)
|
||||
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.Stars = data.stars
|
||||
Metamaps.Backbone.attachCollectionEvents()
|
||||
|
||||
var map = Active.Map
|
||||
var mapper = 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')
|
||||
}
|
||||
|
||||
Map.updateStar()
|
||||
|
||||
// set filter mapper H3 text
|
||||
$('#filter_by_mapper h3').html('MAPPERS')
|
||||
|
||||
// build and render the visualization
|
||||
Visualize.type = 'ForceDirected'
|
||||
JIT.prepareVizData()
|
||||
|
||||
// update filters
|
||||
Filter.reset()
|
||||
|
||||
// reset selected arrays
|
||||
Selected.reset()
|
||||
|
||||
// set the proper mapinfobox content
|
||||
Map.InfoBox.load()
|
||||
|
||||
// these three update the actual filter box with the right list items
|
||||
Filter.checkMetacodes()
|
||||
Filter.checkSynapses()
|
||||
Filter.checkMappers()
|
||||
|
||||
Realtime.startActiveMap()
|
||||
Metamaps.Loading.hide()
|
||||
|
||||
// for mobile
|
||||
$('#header_content').html(map.get('name'))
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/maps/' + id + '/contains.json',
|
||||
success: start
|
||||
})
|
||||
},
|
||||
end: function () {
|
||||
if (Active.Map) {
|
||||
$('.wrapper').removeClass('canEditMap commonsMap')
|
||||
AutoLayout.resetSpiral()
|
||||
|
||||
$('.rightclickmenu').remove()
|
||||
TopicCard.hideCard()
|
||||
SynapseCard.hideCard()
|
||||
Create.newTopic.hide(true) // true means force (and override pinned)
|
||||
Create.newSynapse.hide()
|
||||
Filter.close()
|
||||
Map.InfoBox.close()
|
||||
Realtime.endActiveMap()
|
||||
}
|
||||
},
|
||||
updateStar: function () {
|
||||
if (!Active.Mapper || !Metamaps.Stars) return
|
||||
// update the star/unstar icon
|
||||
if (Metamaps.Stars.find(function (s) { return s.user_id === Active.Mapper.id })) {
|
||||
$('.starMap').addClass('starred')
|
||||
$('.starMap .tooltipsAbove').html('Unstar')
|
||||
} else {
|
||||
$('.starMap').removeClass('starred')
|
||||
$('.starMap .tooltipsAbove').html('Star')
|
||||
}
|
||||
},
|
||||
star: function () {
|
||||
var self = Map
|
||||
|
||||
if (!Active.Map) return
|
||||
$.post('/maps/' + Active.Map.id + '/star')
|
||||
Metamaps.Stars.push({ user_id: Active.Mapper.id, map_id: Active.Map.id })
|
||||
Metamaps.Maps.Starred.add(Active.Map)
|
||||
GlobalUI.notifyUser('Map is now starred')
|
||||
self.updateStar()
|
||||
},
|
||||
unstar: function () {
|
||||
var self = Map
|
||||
|
||||
if (!Active.Map) return
|
||||
$.post('/maps/' + Active.Map.id + '/unstar')
|
||||
Metamaps.Stars = Metamaps.Stars.filter(function (s) { return s.user_id != Active.Mapper.id })
|
||||
Metamaps.Maps.Starred.remove(Active.Map)
|
||||
self.updateStar()
|
||||
},
|
||||
fork: function () {
|
||||
GlobalUI.openLightbox('forkmap')
|
||||
|
||||
var nodes_data = '',
|
||||
synapses_data = ''
|
||||
var nodes_array = []
|
||||
var synapses_array = []
|
||||
// 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
|
||||
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 = 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)
|
||||
|
||||
GlobalUI.CreateMap.topicsToMap = nodes_data
|
||||
GlobalUI.CreateMap.synapsesToMap = synapses_data
|
||||
},
|
||||
leavePrivateMap: function () {
|
||||
var map = Active.Map
|
||||
Metamaps.Maps.Active.remove(map)
|
||||
Metamaps.Maps.Featured.remove(map)
|
||||
Router.home()
|
||||
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 = confirm(confirmString)
|
||||
if (c) {
|
||||
Router.maps(Active.Map.id)
|
||||
}
|
||||
},
|
||||
editedByActiveMapper: function () {
|
||||
if (Active.Mapper) {
|
||||
Metamaps.Mappers.add(Active.Mapper)
|
||||
}
|
||||
},
|
||||
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 = 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)
|
||||
|
||||
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 = 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 += "<a href='" + imageData.encoded_image + "' "
|
||||
downloadMessage += "download='metamap-" + map.id + '-' + mapName + '-' + today + ".png'>DOWNLOAD</a>"
|
||||
GlobalUI.notifyUser(downloadMessage)
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: '/maps/' + 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')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export { CheatSheet, InfoBox }
|
||||
export default Map
|
19
frontend/src/Metamaps/Mapper.js
Normal file
19
frontend/src/Metamaps/Mapper.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Metamaps.Backbone
|
||||
*/
|
||||
|
||||
const Mapper = {
|
||||
// this function is to retrieve a mapper JSON object from the database
|
||||
// @param id = the id of the mapper to retrieve
|
||||
get: function (id, callback) {
|
||||
return fetch(`/users/${id}.json`, {
|
||||
}).then(response => {
|
||||
if (!response.ok) throw response
|
||||
return response.json()
|
||||
}).then(payload => {
|
||||
callback(new Metamaps.Backbone.Mapper(payload))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default Mapper
|
|
@ -1,16 +1,11 @@
|
|||
/* global Metamaps, $ */
|
||||
/* global $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Mobile.js
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.Map
|
||||
*/
|
||||
import Active from './Active'
|
||||
import Map from './Map'
|
||||
|
||||
Metamaps.Mobile = {
|
||||
const Mobile = {
|
||||
init: function () {
|
||||
var self = Metamaps.Mobile
|
||||
var self = Mobile
|
||||
|
||||
$('#menu_icon').click(self.toggleMenu)
|
||||
$('#mobile_menu li a').click(self.liClick)
|
||||
|
@ -22,7 +17,7 @@ Metamaps.Mobile = {
|
|||
$('#header_content').width($(document).width() - 70)
|
||||
},
|
||||
liClick: function () {
|
||||
var self = Metamaps.Mobile
|
||||
var self = Mobile
|
||||
$('#header_content').html($(this).text())
|
||||
self.toggleMenu()
|
||||
},
|
||||
|
@ -30,8 +25,10 @@ Metamaps.Mobile = {
|
|||
$('#mobile_menu').toggle()
|
||||
},
|
||||
titleClick: function () {
|
||||
if (Metamaps.Active.Map) {
|
||||
Metamaps.Map.InfoBox.open()
|
||||
if (Active.Map) {
|
||||
Map.InfoBox.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Mobile
|
16
frontend/src/Metamaps/Mouse.js
Normal file
16
frontend/src/Metamaps/Mouse.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
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
|
||||
}
|
||||
|
||||
export default Mouse
|
|
@ -1,22 +1,22 @@
|
|||
/* global Metamaps, $ */
|
||||
/* global $ */
|
||||
|
||||
/*
|
||||
* Metamaps.Organize.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
Metamaps.Organize = {
|
||||
init: function () {},
|
||||
import _ from 'lodash'
|
||||
|
||||
import $jit from '../patched/JIT'
|
||||
|
||||
import Visualize from './Visualize'
|
||||
import JIT from './JIT'
|
||||
|
||||
const Organize = {
|
||||
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') {
|
||||
var numNodes = _.size(Metamaps.Visualize.mGraph.graph.nodes); // this will always be an integer, the # of nodes on your graph visualization
|
||||
var numNodes = _.size(Visualize.mGraph.graph.nodes); // this will always be an integer, the # of nodes on your graph visualization
|
||||
var numColumns = Math.floor(Math.sqrt(numNodes)) // the number of columns to make an even grid
|
||||
var GRIDSPACE = 400
|
||||
var row = 0
|
||||
var column = 0
|
||||
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
|
||||
Visualize.mGraph.graph.eachNode(function (n) {
|
||||
if (column == numColumns) {
|
||||
column = 0
|
||||
row += 1
|
||||
|
@ -27,14 +27,14 @@ Metamaps.Organize = {
|
|||
n.setPos(newPos, 'end')
|
||||
column += 1
|
||||
})
|
||||
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout)
|
||||
Visualize.mGraph.animate(JIT.ForceDirected.animateSavedLayout)
|
||||
} else if (layout == 'grid_full') {
|
||||
// this will always be an integer, the # of nodes on your graph visualization
|
||||
var numNodes = _.size(Metamaps.Visualize.mGraph.graph.nodes)
|
||||
var numNodes = _.size(Visualize.mGraph.graph.nodes)
|
||||
// var numColumns = Math.floor(Math.sqrt(numNodes)) // the number of columns to make an even grid
|
||||
// var GRIDSPACE = 400
|
||||
var height = Metamaps.Visualize.mGraph.canvas.getSize(0).height
|
||||
var width = Metamaps.Visualize.mGraph.canvas.getSize(0).width
|
||||
var height = Visualize.mGraph.canvas.getSize(0).height
|
||||
var width = Visualize.mGraph.canvas.getSize(0).width
|
||||
var totalArea = height * width
|
||||
var cellArea = totalArea / numNodes
|
||||
var ratio = height / width
|
||||
|
@ -45,7 +45,7 @@ Metamaps.Organize = {
|
|||
var totalCells = row * column
|
||||
|
||||
if (totalCells)
|
||||
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
|
||||
Visualize.mGraph.graph.eachNode(function (n) {
|
||||
if (column == numColumns) {
|
||||
column = 0
|
||||
row += 1
|
||||
|
@ -56,7 +56,7 @@ Metamaps.Organize = {
|
|||
n.setPos(newPos, 'end')
|
||||
column += 1
|
||||
})
|
||||
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout)
|
||||
Visualize.mGraph.animate(JIT.ForceDirected.animateSavedLayout)
|
||||
} else if (layout == 'radial') {
|
||||
var centerX = centerNode.getPos().x
|
||||
var centerY = centerNode.getPos().y
|
||||
|
@ -88,16 +88,16 @@ Metamaps.Organize = {
|
|||
})
|
||||
}
|
||||
radial(centerNode, 1, 0)
|
||||
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout)
|
||||
Visualize.mGraph.animate(JIT.ForceDirected.animateSavedLayout)
|
||||
} else if (layout == 'center_viewport') {
|
||||
var lowX = 0,
|
||||
lowY = 0,
|
||||
highX = 0,
|
||||
highY = 0
|
||||
var oldOriginX = Metamaps.Visualize.mGraph.canvas.translateOffsetX
|
||||
var oldOriginY = Metamaps.Visualize.mGraph.canvas.translateOffsetY
|
||||
var oldOriginX = Visualize.mGraph.canvas.translateOffsetX
|
||||
var oldOriginY = Visualize.mGraph.canvas.translateOffsetY
|
||||
|
||||
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
|
||||
Visualize.mGraph.graph.eachNode(function (n) {
|
||||
if (n.id === 1) {
|
||||
lowX = n.getPos().x
|
||||
lowY = n.getPos().y
|
||||
|
@ -114,4 +114,6 @@ Metamaps.Organize = {
|
|||
var newOriginY = (lowY + highY) / 2
|
||||
} else alert('please call function with a valid layout dammit!')
|
||||
}
|
||||
}; // end Metamaps.Organize
|
||||
}
|
||||
|
||||
export default Organize
|
|
@ -1,19 +1,16 @@
|
|||
/* global Metamaps, $ */
|
||||
/* global $ */
|
||||
|
||||
/*
|
||||
* Metamaps.PasteInput.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Import
|
||||
* - Metamaps.AutoLayout
|
||||
*/
|
||||
import AutoLayout from './AutoLayout'
|
||||
import Import from './Import'
|
||||
import TopicCard from './TopicCard'
|
||||
import Util from './Util'
|
||||
|
||||
Metamaps.PasteInput = {
|
||||
const PasteInput = {
|
||||
// thanks to https://github.com/kevva/url-regex
|
||||
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 = Metamaps.PasteInput
|
||||
var self = PasteInput
|
||||
|
||||
// intercept dragged files
|
||||
// see http://stackoverflow.com/questions/6756583
|
||||
|
@ -24,7 +21,7 @@ Metamaps.PasteInput = {
|
|||
window.addEventListener("drop", function(e) {
|
||||
e = e || event;
|
||||
e.preventDefault();
|
||||
var coords = Metamaps.Util.pixelsToCoords({ x: e.clientX, y: e.clientY })
|
||||
var coords = Util.pixelsToCoords({ x: e.clientX, y: e.clientY })
|
||||
if (e.dataTransfer.files.length > 0) {
|
||||
var fileReader = new FileReader()
|
||||
var text = fileReader.readAsText(e.dataTransfer.files[0])
|
||||
|
@ -58,7 +55,7 @@ Metamaps.PasteInput = {
|
|||
},
|
||||
|
||||
handle: function(text, coords) {
|
||||
var self = Metamaps.PasteInput
|
||||
var self = PasteInput
|
||||
|
||||
if (text.match(self.URL_REGEX)) {
|
||||
self.handleURL(text, coords)
|
||||
|
@ -74,13 +71,13 @@ Metamaps.PasteInput = {
|
|||
handleURL: function (text, coords) {
|
||||
var title = 'Link'
|
||||
if (!coords || !coords.x || !coords.y) {
|
||||
coords = Metamaps.AutoLayout.getNextCoord()
|
||||
coords = AutoLayout.getNextCoord()
|
||||
}
|
||||
|
||||
var import_id = null // don't store a cidMapping
|
||||
var permission = null // use default
|
||||
|
||||
Metamaps.Import.createTopicWithParameters(
|
||||
Import.createTopicWithParameters(
|
||||
title,
|
||||
'Reference', // metacode - todo fix
|
||||
permission,
|
||||
|
@ -91,7 +88,7 @@ Metamaps.PasteInput = {
|
|||
import_id,
|
||||
{
|
||||
success: function(topic) {
|
||||
Metamaps.TopicCard.showCard(topic.get('node'), function() {
|
||||
TopicCard.showCard(topic.get('node'), function() {
|
||||
$('#showcard #titleActivator').click()
|
||||
.find('textarea, input').focus()
|
||||
})
|
||||
|
@ -101,10 +98,12 @@ Metamaps.PasteInput = {
|
|||
},
|
||||
|
||||
handleJSON: function (text) {
|
||||
Metamaps.Import.handleJSON(text)
|
||||
Import.handleJSON(text)
|
||||
},
|
||||
|
||||
handleTSV: function (text) {
|
||||
Metamaps.Import.handleTSV(text)
|
||||
Import.handleTSV(text)
|
||||
}
|
||||
}
|
||||
|
||||
export default PasteInput
|
7
frontend/src/Metamaps/ReactComponents.js
Normal file
7
frontend/src/Metamaps/ReactComponents.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import Maps from '../components/Maps'
|
||||
|
||||
const ReactComponents = {
|
||||
Maps
|
||||
}
|
||||
|
||||
export default ReactComponents
|
File diff suppressed because it is too large
Load diff
252
frontend/src/Metamaps/Router.js
Normal file
252
frontend/src/Metamaps/Router.js
Normal file
|
@ -0,0 +1,252 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import Backbone from 'backbone'
|
||||
//TODO is this line good or bad?
|
||||
//Backbone.$ = window.$
|
||||
|
||||
import Active from './Active'
|
||||
import GlobalUI from './GlobalUI'
|
||||
import JIT from './JIT'
|
||||
import Map from './Map'
|
||||
import Topic from './Topic'
|
||||
import Views from './Views'
|
||||
import Visualize from './Visualize'
|
||||
|
||||
/*
|
||||
* Metamaps.Router.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Loading
|
||||
* - Metamaps.Maps
|
||||
*/
|
||||
|
||||
const _Router = Backbone.Router.extend({
|
||||
currentPage: '',
|
||||
currentSection: '',
|
||||
timeoutId: undefined,
|
||||
routes: {
|
||||
'': 'home', // #home
|
||||
'explore/:section': 'explore', // #explore/active
|
||||
'explore/:section/:id': 'explore', // #explore/mapper/1234
|
||||
'maps/:id': 'maps' // #maps/7
|
||||
},
|
||||
home: function () {
|
||||
let self = this
|
||||
clearTimeout(this.timeoutId)
|
||||
|
||||
if (Active.Mapper) document.title = 'Explore Active Maps | Metamaps'
|
||||
else document.title = 'Home | Metamaps'
|
||||
|
||||
this.currentSection = ''
|
||||
this.currentPage = ''
|
||||
$('.wrapper').removeClass('mapPage topicPage')
|
||||
|
||||
var classes = Active.Mapper ? 'homePage explorePage' : 'homePage'
|
||||
$('.wrapper').addClass(classes)
|
||||
|
||||
var navigate = function () {
|
||||
self.timeoutId = setTimeout(function () {
|
||||
self.navigate('')
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// all this only for the logged in home page
|
||||
if (Active.Mapper) {
|
||||
$('.homeButton a').attr('href', '/')
|
||||
GlobalUI.hideDiv('#yield')
|
||||
|
||||
GlobalUI.showDiv('#explore')
|
||||
|
||||
Views.ExploreMaps.setCollection(Metamaps.Maps.Active)
|
||||
if (Metamaps.Maps.Active.length === 0) {
|
||||
Metamaps.Maps.Active.getMaps(navigate) // this will trigger an explore maps render
|
||||
} else {
|
||||
Views.ExploreMaps.render(navigate)
|
||||
}
|
||||
} else {
|
||||
// logged out home page
|
||||
GlobalUI.hideDiv('#explore')
|
||||
GlobalUI.showDiv('#yield')
|
||||
this.timeoutId = setTimeout(navigate, 500)
|
||||
}
|
||||
|
||||
GlobalUI.hideDiv('#infovis')
|
||||
GlobalUI.hideDiv('#instructions')
|
||||
Map.end()
|
||||
Topic.end()
|
||||
Active.Map = null
|
||||
Active.Topic = null
|
||||
},
|
||||
explore: function (section, id) {
|
||||
var self = this
|
||||
clearTimeout(this.timeoutId)
|
||||
|
||||
// just capitalize the variable section
|
||||
// either 'featured', 'mapper', or 'active'
|
||||
var capitalize = section.charAt(0).toUpperCase() + section.slice(1)
|
||||
|
||||
if (section === 'shared' || section === 'featured' || section === 'active' || section === 'starred') {
|
||||
document.title = 'Explore ' + capitalize + ' Maps | Metamaps'
|
||||
} else if (section === 'mapper') {
|
||||
$.ajax({
|
||||
url: '/users/' + id + '.json',
|
||||
success: function (response) {
|
||||
document.title = response.name + ' | Metamaps'
|
||||
},
|
||||
error: function () {}
|
||||
})
|
||||
} else if (section === 'mine') {
|
||||
document.title = 'Explore My Maps | Metamaps'
|
||||
}
|
||||
|
||||
if (Active.Mapper && section != 'mapper') $('.homeButton a').attr('href', '/explore/' + section)
|
||||
$('.wrapper').removeClass('homePage mapPage topicPage')
|
||||
$('.wrapper').addClass('explorePage')
|
||||
|
||||
this.currentSection = 'explore'
|
||||
this.currentPage = section
|
||||
|
||||
// this will mean it's a mapper page being loaded
|
||||
if (id) {
|
||||
if (Metamaps.Maps.Mapper.mapperId !== id) {
|
||||
// empty the collection if we are trying to load the maps
|
||||
// collection of a different mapper than we had previously
|
||||
Metamaps.Maps.Mapper.reset()
|
||||
Metamaps.Maps.Mapper.page = 1
|
||||
}
|
||||
Metamaps.Maps.Mapper.mapperId = id
|
||||
}
|
||||
|
||||
Views.ExploreMaps.setCollection(Metamaps.Maps[capitalize])
|
||||
|
||||
var navigate = function () {
|
||||
var path = '/explore/' + self.currentPage
|
||||
|
||||
// alter url if for mapper profile page
|
||||
if (self.currentPage === 'mapper') {
|
||||
path += '/' + Metamaps.Maps.Mapper.mapperId
|
||||
}
|
||||
|
||||
self.navigate(path)
|
||||
}
|
||||
var navigateTimeout = function () {
|
||||
self.timeoutId = setTimeout(navigate, 300)
|
||||
}
|
||||
if (Metamaps.Maps[capitalize].length === 0) {
|
||||
Metamaps.Loading.show()
|
||||
setTimeout(function () {
|
||||
Metamaps.Maps[capitalize].getMaps(navigate) // this will trigger an explore maps render
|
||||
}, 300) // wait 300 milliseconds till the other animations are done to do the fetch
|
||||
} else {
|
||||
if (id) {
|
||||
Views.ExploreMaps.fetchUserThenRender(navigateTimeout)
|
||||
} else {
|
||||
Views.ExploreMaps.render(navigateTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
GlobalUI.showDiv('#explore')
|
||||
GlobalUI.hideDiv('#yield')
|
||||
GlobalUI.hideDiv('#infovis')
|
||||
GlobalUI.hideDiv('#instructions')
|
||||
Map.end()
|
||||
Topic.end()
|
||||
Active.Map = null
|
||||
Active.Topic = null
|
||||
},
|
||||
maps: function (id) {
|
||||
clearTimeout(this.timeoutId)
|
||||
|
||||
document.title = 'Map ' + id + ' | Metamaps'
|
||||
|
||||
this.currentSection = 'map'
|
||||
this.currentPage = id
|
||||
|
||||
$('.wrapper').removeClass('homePage explorePage topicPage')
|
||||
$('.wrapper').addClass('mapPage')
|
||||
// another class will be added to wrapper if you
|
||||
// can edit this map '.canEditMap'
|
||||
|
||||
GlobalUI.hideDiv('#yield')
|
||||
GlobalUI.hideDiv('#explore')
|
||||
|
||||
// clear the visualization, if there was one, before showing its div again
|
||||
if (Visualize.mGraph) {
|
||||
Visualize.mGraph.graph.empty()
|
||||
Visualize.mGraph.plot()
|
||||
JIT.centerMap(Visualize.mGraph.canvas)
|
||||
}
|
||||
GlobalUI.showDiv('#infovis')
|
||||
Topic.end()
|
||||
Active.Topic = null
|
||||
|
||||
Metamaps.Loading.show()
|
||||
Map.end()
|
||||
Map.launch(id)
|
||||
},
|
||||
topics: function (id) {
|
||||
clearTimeout(this.timeoutId)
|
||||
|
||||
document.title = 'Topic ' + id + ' | Metamaps'
|
||||
|
||||
this.currentSection = 'topic'
|
||||
this.currentPage = id
|
||||
|
||||
$('.wrapper').removeClass('homePage explorePage mapPage')
|
||||
$('.wrapper').addClass('topicPage')
|
||||
|
||||
GlobalUI.hideDiv('#yield')
|
||||
GlobalUI.hideDiv('#explore')
|
||||
|
||||
// clear the visualization, if there was one, before showing its div again
|
||||
if (Visualize.mGraph) {
|
||||
Visualize.mGraph.graph.empty()
|
||||
Visualize.mGraph.plot()
|
||||
JIT.centerMap(Visualize.mGraph.canvas)
|
||||
}
|
||||
GlobalUI.showDiv('#infovis')
|
||||
Map.end()
|
||||
Active.Map = null
|
||||
|
||||
Topic.end()
|
||||
Topic.launch(id)
|
||||
}
|
||||
})
|
||||
|
||||
const Router = new _Router()
|
||||
|
||||
Router.intercept = function (evt) {
|
||||
var segments
|
||||
|
||||
var href = {
|
||||
prop: $(this).prop('href'),
|
||||
attr: $(this).attr('href')
|
||||
}
|
||||
var root = window.location.protocol + '//' + window.location.host + Backbone.history.options.root
|
||||
|
||||
if (href.prop && href.prop === root) href.attr = ''
|
||||
|
||||
if (href.prop && href.prop.slice(0, root.length) === root) {
|
||||
evt.preventDefault()
|
||||
|
||||
segments = href.attr.split('/')
|
||||
segments.splice(0, 1) // pop off the element created by the first /
|
||||
|
||||
if (href.attr === '') {
|
||||
Router.home()
|
||||
} else {
|
||||
Router[segments[0]](segments[1], segments[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Router.init = function () {
|
||||
Backbone.history.start({
|
||||
silent: true,
|
||||
pushState: true,
|
||||
root: '/'
|
||||
})
|
||||
$(document).on('click', 'a[data-router="true"]', Router.intercept)
|
||||
}
|
||||
|
||||
export default Router
|
11
frontend/src/Metamaps/Selected.js
Normal file
11
frontend/src/Metamaps/Selected.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
const Selected = {
|
||||
reset: function () {
|
||||
var self = Metamaps.Selected
|
||||
self.Nodes = []
|
||||
self.Edges = []
|
||||
},
|
||||
Nodes: [],
|
||||
Edges: []
|
||||
}
|
||||
|
||||
export default Selected
|
21
frontend/src/Metamaps/Settings.js
Normal file
21
frontend/src/Metamaps/Settings.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
const Settings = {
|
||||
embed: false, // indicates that the app is on a page that is optimized for embedding in iFrames on other web pages
|
||||
sandbox: false, // puts the app into a mode (when true) where it only creates data locally, and isn't writing it to the database
|
||||
colors: {
|
||||
background: '#344A58',
|
||||
synapses: {
|
||||
normal: '#888888',
|
||||
hover: '#888888',
|
||||
selected: '#FFFFFF'
|
||||
},
|
||||
topics: {
|
||||
selected: '#FFFFFF'
|
||||
},
|
||||
labels: {
|
||||
background: '#18202E',
|
||||
text: '#DDD'
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default Settings
|
|
@ -1,23 +1,25 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import Active from './Active'
|
||||
import Control from './Control'
|
||||
import Create from './Create'
|
||||
import JIT from './JIT'
|
||||
import Map from './Map'
|
||||
import Selected from './Selected'
|
||||
import Settings from './Settings'
|
||||
import Visualize from './Visualize'
|
||||
|
||||
/*
|
||||
* Metamaps.Synapse.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Backbone
|
||||
* - Metamaps.Control
|
||||
* - Metamaps.Create
|
||||
* - Metamaps.JIT
|
||||
* - Metamaps.Map
|
||||
* - Metamaps.Mappings
|
||||
* - Metamaps.Selected
|
||||
* - Metamaps.Settings
|
||||
* - Metamaps.Synapses
|
||||
* - Metamaps.Topics
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
|
||||
Metamaps.Synapse = {
|
||||
const Synapse = {
|
||||
// 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) {
|
||||
|
@ -52,18 +54,18 @@ Metamaps.Synapse = {
|
|||
*
|
||||
*/
|
||||
renderSynapse: function (mapping, synapse, node1, node2, createNewInDB) {
|
||||
var self = Metamaps.Synapse
|
||||
var self = Synapse
|
||||
|
||||
var edgeOnViz
|
||||
|
||||
var newedge = synapse.createEdge(mapping)
|
||||
|
||||
Metamaps.Visualize.mGraph.graph.addAdjacence(node1, node2, newedge.data)
|
||||
edgeOnViz = Metamaps.Visualize.mGraph.graph.getAdjacence(node1.id, node2.id)
|
||||
Visualize.mGraph.graph.addAdjacence(node1, node2, newedge.data)
|
||||
edgeOnViz = Visualize.mGraph.graph.getAdjacence(node1.id, node2.id)
|
||||
synapse.set('edge', edgeOnViz)
|
||||
synapse.updateEdge() // links the synapse and the mapping to the edge
|
||||
|
||||
Metamaps.Control.selectEdge(edgeOnViz)
|
||||
Control.selectEdge(edgeOnViz)
|
||||
|
||||
var mappingSuccessCallback = function (mappingModel, response) {
|
||||
var newSynapseData = {
|
||||
|
@ -71,17 +73,17 @@ Metamaps.Synapse = {
|
|||
mappableid: mappingModel.get('mappable_id')
|
||||
}
|
||||
|
||||
$(document).trigger(Metamaps.JIT.events.newSynapse, [newSynapseData])
|
||||
$(document).trigger(JIT.events.newSynapse, [newSynapseData])
|
||||
}
|
||||
var synapseSuccessCallback = function (synapseModel, response) {
|
||||
if (Metamaps.Active.Map) {
|
||||
if (Active.Map) {
|
||||
mapping.save({ mappable_id: synapseModel.id }, {
|
||||
success: mappingSuccessCallback
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (!Metamaps.Settings.sandbox && createNewInDB) {
|
||||
if (!Settings.sandbox && createNewInDB) {
|
||||
if (synapse.isNew()) {
|
||||
synapse.save(null, {
|
||||
success: synapseSuccessCallback,
|
||||
|
@ -89,7 +91,7 @@ Metamaps.Synapse = {
|
|||
console.log('error saving synapse to database')
|
||||
}
|
||||
})
|
||||
} else if (!synapse.isNew() && Metamaps.Active.Map) {
|
||||
} else if (!synapse.isNew() && Active.Map) {
|
||||
mapping.save(null, {
|
||||
success: mappingSuccessCallback
|
||||
})
|
||||
|
@ -97,7 +99,7 @@ Metamaps.Synapse = {
|
|||
}
|
||||
},
|
||||
createSynapseLocally: function () {
|
||||
var self = Metamaps.Synapse,
|
||||
var self = Synapse,
|
||||
topic1,
|
||||
topic2,
|
||||
node1,
|
||||
|
@ -105,27 +107,27 @@ Metamaps.Synapse = {
|
|||
synapse,
|
||||
mapping
|
||||
|
||||
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
|
||||
$(document).trigger(Map.events.editedByActiveMapper)
|
||||
|
||||
// for each node in this array we will create a synapse going to the position2 node.
|
||||
var synapsesToCreate = []
|
||||
|
||||
topic2 = Metamaps.Topics.get(Metamaps.Create.newSynapse.topic2id)
|
||||
topic2 = Metamaps.Topics.get(Create.newSynapse.topic2id)
|
||||
node2 = topic2.get('node')
|
||||
|
||||
var len = Metamaps.Selected.Nodes.length
|
||||
var len = Selected.Nodes.length
|
||||
if (len == 0) {
|
||||
topic1 = Metamaps.Topics.get(Metamaps.Create.newSynapse.topic1id)
|
||||
topic1 = Metamaps.Topics.get(Create.newSynapse.topic1id)
|
||||
synapsesToCreate[0] = topic1.get('node')
|
||||
} else if (len > 0) {
|
||||
synapsesToCreate = Metamaps.Selected.Nodes
|
||||
synapsesToCreate = Selected.Nodes
|
||||
}
|
||||
|
||||
for (var i = 0; i < synapsesToCreate.length; i++) {
|
||||
node1 = synapsesToCreate[i]
|
||||
topic1 = node1.getData('topic')
|
||||
synapse = new Metamaps.Backbone.Synapse({
|
||||
desc: Metamaps.Create.newSynapse.description,
|
||||
desc: Create.newSynapse.description,
|
||||
node1_id: topic1.isNew() ? topic1.cid : topic1.id,
|
||||
node2_id: topic2.isNew() ? topic2.cid : topic2.id,
|
||||
})
|
||||
|
@ -141,10 +143,10 @@ Metamaps.Synapse = {
|
|||
self.renderSynapse(mapping, synapse, node1, node2, true)
|
||||
} // for each in synapsesToCreate
|
||||
|
||||
Metamaps.Create.newSynapse.hide()
|
||||
Create.newSynapse.hide()
|
||||
},
|
||||
getSynapseFromAutocomplete: function (id) {
|
||||
var self = Metamaps.Synapse,
|
||||
var self = Synapse,
|
||||
topic1,
|
||||
topic2,
|
||||
node1,
|
||||
|
@ -158,12 +160,14 @@ Metamaps.Synapse = {
|
|||
})
|
||||
Metamaps.Mappings.add(mapping)
|
||||
|
||||
topic1 = Metamaps.Topics.get(Metamaps.Create.newSynapse.topic1id)
|
||||
topic1 = Metamaps.Topics.get(Create.newSynapse.topic1id)
|
||||
node1 = topic1.get('node')
|
||||
topic2 = Metamaps.Topics.get(Metamaps.Create.newSynapse.topic2id)
|
||||
topic2 = Metamaps.Topics.get(Create.newSynapse.topic2id)
|
||||
node2 = topic2.get('node')
|
||||
Metamaps.Create.newSynapse.hide()
|
||||
Create.newSynapse.hide()
|
||||
|
||||
self.renderSynapse(mapping, synapse, node1, node2, true)
|
||||
}
|
||||
}; // end Metamaps.Synapse
|
||||
}
|
||||
|
||||
export default Synapse
|
|
@ -1,18 +1,13 @@
|
|||
/* global Metamaps, $ */
|
||||
/* global $ */
|
||||
import Active from './Active'
|
||||
import Control from './Control'
|
||||
import Mapper from './Mapper'
|
||||
import Visualize from './Visualize'
|
||||
|
||||
/*
|
||||
* Metamaps.SynapseCard.js
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.Control
|
||||
* - Metamaps.Mapper
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
Metamaps.SynapseCard = {
|
||||
const SynapseCard = {
|
||||
openSynapseCard: null,
|
||||
showCard: function (edge, e) {
|
||||
var self = Metamaps.SynapseCard
|
||||
var self = SynapseCard
|
||||
|
||||
// reset so we don't interfere with other edges, but first, save its x and y
|
||||
var myX = $('#edit_synapse').css('left')
|
||||
|
@ -20,7 +15,7 @@ Metamaps.SynapseCard = {
|
|||
$('#edit_synapse').remove()
|
||||
|
||||
// so label is missing while editing
|
||||
Metamaps.Control.deselectEdge(edge)
|
||||
Control.deselectEdge(edge)
|
||||
|
||||
var index = edge.getData('displayIndex') ? edge.getData('displayIndex') : 0
|
||||
var synapse = edge.getData('synapses')[index]; // for now, just get the first synapse
|
||||
|
@ -30,9 +25,9 @@ Metamaps.SynapseCard = {
|
|||
var edit_div = document.createElement('div')
|
||||
edit_div.innerHTML = '<div id="editSynUpperBar"></div><div id="editSynLowerBar"></div>'
|
||||
edit_div.setAttribute('id', 'edit_synapse')
|
||||
if (synapse.authorizeToEdit(Metamaps.Active.Mapper)) {
|
||||
if (synapse.authorizeToEdit(Active.Mapper)) {
|
||||
edit_div.className = 'permission canEdit'
|
||||
edit_div.className += synapse.authorizePermissionChange(Metamaps.Active.Mapper) ? ' yourEdge' : ''
|
||||
edit_div.className += synapse.authorizePermissionChange(Active.Mapper) ? ' yourEdge' : ''
|
||||
} else {
|
||||
edit_div.className = 'permission cannotEdit'
|
||||
}
|
||||
|
@ -58,11 +53,11 @@ Metamaps.SynapseCard = {
|
|||
|
||||
hideCard: function () {
|
||||
$('#edit_synapse').remove()
|
||||
Metamaps.SynapseCard.openSynapseCard = null
|
||||
SynapseCard.openSynapseCard = null
|
||||
},
|
||||
|
||||
populateShowCard: function (edge, synapse) {
|
||||
var self = Metamaps.SynapseCard
|
||||
var self = SynapseCard
|
||||
|
||||
self.add_synapse_count(edge)
|
||||
self.add_desc_form(synapse)
|
||||
|
@ -94,7 +89,7 @@ Metamaps.SynapseCard = {
|
|||
|
||||
// if edge data is blank or just whitespace, populate it with data_nil
|
||||
if ($('#edit_synapse_desc').html().trim() == '') {
|
||||
if (synapse.authorizeToEdit(Metamaps.Active.Mapper)) {
|
||||
if (synapse.authorizeToEdit(Active.Mapper)) {
|
||||
$('#edit_synapse_desc').html(data_nil)
|
||||
} else {
|
||||
$('#edit_synapse_desc').html('(no description)')
|
||||
|
@ -109,8 +104,8 @@ Metamaps.SynapseCard = {
|
|||
synapse.set('desc', desc)
|
||||
}
|
||||
synapse.trigger('saved')
|
||||
Metamaps.Control.selectEdge(synapse.get('edge'))
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Control.selectEdge(synapse.get('edge'))
|
||||
Visualize.mGraph.plot()
|
||||
})
|
||||
},
|
||||
add_drop_down: function (edge, synapse) {
|
||||
|
@ -152,8 +147,8 @@ Metamaps.SynapseCard = {
|
|||
e.stopPropagation()
|
||||
var index = parseInt($(this).attr('data-synapse-index'))
|
||||
edge.setData('displayIndex', index)
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Metamaps.SynapseCard.showCard(edge, false)
|
||||
Visualize.mGraph.plot()
|
||||
SynapseCard.showCard(edge, false)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
@ -167,7 +162,7 @@ Metamaps.SynapseCard = {
|
|||
var setMapperImage = function (mapper) {
|
||||
$('#edgeUser img').attr('src', mapper.get('image'))
|
||||
}
|
||||
Metamaps.Mapper.get(synapse.get('user_id'), setMapperImage)
|
||||
Mapper.get(synapse.get('user_id'), setMapperImage)
|
||||
},
|
||||
|
||||
add_perms_form: function (synapse) {
|
||||
|
@ -210,7 +205,7 @@ Metamaps.SynapseCard = {
|
|||
$('#edit_synapse .permissionSelect').remove()
|
||||
}
|
||||
|
||||
if (synapse.authorizePermissionChange(Metamaps.Active.Mapper)) {
|
||||
if (synapse.authorizePermissionChange(Active.Mapper)) {
|
||||
$('#edit_synapse.yourEdge .mapPerm').click(openPermissionSelect)
|
||||
$('#edit_synapse').click(hidePermissionSelect)
|
||||
}
|
||||
|
@ -257,7 +252,7 @@ Metamaps.SynapseCard = {
|
|||
$('#edit_synapse_right').addClass('checked')
|
||||
}
|
||||
|
||||
if (synapse.authorizeToEdit(Metamaps.Active.Mapper)) {
|
||||
if (synapse.authorizeToEdit(Active.Mapper)) {
|
||||
$('#edit_synapse_left, #edit_synapse_right').click(function () {
|
||||
$(this).toggleClass('checked')
|
||||
|
||||
|
@ -281,8 +276,10 @@ Metamaps.SynapseCard = {
|
|||
node1_id: dir[0],
|
||||
node2_id: dir[1]
|
||||
})
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Visualize.mGraph.plot()
|
||||
})
|
||||
} // if
|
||||
} // add_direction_form
|
||||
}; // end Metamaps.SynapseCard
|
||||
}
|
||||
|
||||
export default SynapseCard
|
|
@ -1,33 +1,35 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import $jit from '../patched/JIT'
|
||||
|
||||
import Active from './Active'
|
||||
import AutoLayout from './AutoLayout'
|
||||
import Create from './Create'
|
||||
import Filter from './Filter'
|
||||
import GlobalUI from './GlobalUI'
|
||||
import JIT from './JIT'
|
||||
import Map from './Map'
|
||||
import Router from './Router'
|
||||
import Selected from './Selected'
|
||||
import Settings from './Settings'
|
||||
import SynapseCard from './SynapseCard'
|
||||
import TopicCard from './TopicCard'
|
||||
import Util from './Util'
|
||||
import Visualize from './Visualize'
|
||||
|
||||
|
||||
/*
|
||||
* Metamaps.Topic.js.erb
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.Backbone
|
||||
* - Metamaps.Backbone
|
||||
* - Metamaps.Create
|
||||
* - Metamaps.Creators
|
||||
* - Metamaps.Famous
|
||||
* - Metamaps.Filter
|
||||
* - Metamaps.GlobalUI
|
||||
* - Metamaps.JIT
|
||||
* - Metamaps.Mappings
|
||||
* - Metamaps.Selected
|
||||
* - Metamaps.Settings
|
||||
* - Metamaps.SynapseCard
|
||||
* - Metamaps.Synapses
|
||||
* - Metamaps.TopicCard
|
||||
* - Metamaps.Topics
|
||||
* - Metamaps.Util
|
||||
* - Metamaps.Visualize
|
||||
* - Metamaps.tempInit
|
||||
* - Metamaps.tempNode
|
||||
* - Metamaps.tempNode2
|
||||
*/
|
||||
|
||||
Metamaps.Topic = {
|
||||
const Topic = {
|
||||
// this function is to retrieve a topic JSON object from the database
|
||||
// @param id = the id of the topic to retrieve
|
||||
get: function (id, callback) {
|
||||
|
@ -61,7 +63,7 @@ Metamaps.Topic = {
|
|||
launch: function (id) {
|
||||
var bb = Metamaps.Backbone
|
||||
var start = function (data) {
|
||||
Metamaps.Active.Topic = new bb.Topic(data.topic)
|
||||
Active.Topic = new bb.Topic(data.topic)
|
||||
Metamaps.Creators = new bb.MapperCollection(data.creators)
|
||||
Metamaps.Topics = new bb.TopicCollection([data.topic].concat(data.relatives))
|
||||
Metamaps.Synapses = new bb.SynapseCollection(data.synapses)
|
||||
|
@ -71,22 +73,22 @@ Metamaps.Topic = {
|
|||
$('#filter_by_mapper h3').html('CREATORS')
|
||||
|
||||
// build and render the visualization
|
||||
Metamaps.Visualize.type = 'RGraph'
|
||||
Metamaps.JIT.prepareVizData()
|
||||
Visualize.type = 'RGraph'
|
||||
JIT.prepareVizData()
|
||||
|
||||
// update filters
|
||||
Metamaps.Filter.reset()
|
||||
Filter.reset()
|
||||
|
||||
// reset selected arrays
|
||||
Metamaps.Selected.reset()
|
||||
Selected.reset()
|
||||
|
||||
// these three update the actual filter box with the right list items
|
||||
Metamaps.Filter.checkMetacodes()
|
||||
Metamaps.Filter.checkSynapses()
|
||||
Metamaps.Filter.checkMappers()
|
||||
Filter.checkMetacodes()
|
||||
Filter.checkSynapses()
|
||||
Filter.checkMappers()
|
||||
|
||||
// for mobile
|
||||
$('#header_content').html(Metamaps.Active.Topic.get('name'))
|
||||
$('#header_content').html(Active.Topic.get('name'))
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
|
@ -95,25 +97,25 @@ Metamaps.Topic = {
|
|||
})
|
||||
},
|
||||
end: function () {
|
||||
if (Metamaps.Active.Topic) {
|
||||
if (Active.Topic) {
|
||||
$('.rightclickmenu').remove()
|
||||
Metamaps.TopicCard.hideCard()
|
||||
Metamaps.SynapseCard.hideCard()
|
||||
Metamaps.Filter.close()
|
||||
TopicCard.hideCard()
|
||||
SynapseCard.hideCard()
|
||||
Filter.close()
|
||||
}
|
||||
},
|
||||
centerOn: function (nodeid, callback) {
|
||||
// don't clash with fetchRelatives
|
||||
if (!Metamaps.Visualize.mGraph.busy) {
|
||||
Metamaps.Visualize.mGraph.onClick(nodeid, {
|
||||
if (!Visualize.mGraph.busy) {
|
||||
Visualize.mGraph.onClick(nodeid, {
|
||||
hideLabels: false,
|
||||
duration: 1000,
|
||||
onComplete: function () {
|
||||
if (callback) callback()
|
||||
}
|
||||
})
|
||||
Metamaps.Router.navigate('/topics/' + nodeid)
|
||||
Metamaps.Active.Topic = Metamaps.Topics.get(nodeid)
|
||||
Router.navigate('/topics/' + nodeid)
|
||||
Active.Topic = Metamaps.Topics.get(nodeid)
|
||||
}
|
||||
},
|
||||
fetchRelatives: function (nodes, metacode_id) {
|
||||
|
@ -131,7 +133,7 @@ Metamaps.Topic = {
|
|||
|
||||
var successCallback;
|
||||
successCallback = function (data) {
|
||||
if (Metamaps.Visualize.mGraph.busy) {
|
||||
if (Visualize.mGraph.busy) {
|
||||
// don't clash with centerOn
|
||||
window.setTimeout(function() { successCallback(data) }, 100)
|
||||
return
|
||||
|
@ -144,8 +146,8 @@ Metamaps.Topic = {
|
|||
topicColl.add(topic)
|
||||
var synapseColl = new Metamaps.Backbone.SynapseCollection(data.synapses)
|
||||
|
||||
var graph = Metamaps.JIT.convertModelsToJIT(topicColl, synapseColl)[0]
|
||||
Metamaps.Visualize.mGraph.op.sum(graph, {
|
||||
var graph = JIT.convertModelsToJIT(topicColl, synapseColl)[0]
|
||||
Visualize.mGraph.op.sum(graph, {
|
||||
type: 'fade',
|
||||
duration: 500,
|
||||
hideLabels: false
|
||||
|
@ -153,7 +155,7 @@ Metamaps.Topic = {
|
|||
|
||||
var i, l, t, s
|
||||
|
||||
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
|
||||
Visualize.mGraph.graph.eachNode(function (n) {
|
||||
t = Metamaps.Topics.get(n.id)
|
||||
t.set({ node: n }, { silent: true })
|
||||
t.updateNode()
|
||||
|
@ -189,8 +191,8 @@ Metamaps.Topic = {
|
|||
|
||||
// opts is additional options in a hash
|
||||
// TODO: move createNewInDB and permitCerateSYnapseAfter into opts
|
||||
renderTopic: function (mapping, topic, createNewInDB, permitCreateSynapseAfter, opts) {
|
||||
var self = Metamaps.Topic
|
||||
renderTopic: function (mapping, topic, createNewInDB, permitCreateSynapseAfter, opts = {}) {
|
||||
var self = Topic
|
||||
|
||||
var nodeOnViz, tempPos
|
||||
|
||||
|
@ -198,56 +200,56 @@ Metamaps.Topic = {
|
|||
|
||||
var midpoint = {}, pixelPos
|
||||
|
||||
if (!$.isEmptyObject(Metamaps.Visualize.mGraph.graph.nodes)) {
|
||||
Metamaps.Visualize.mGraph.graph.addNode(newnode)
|
||||
nodeOnViz = Metamaps.Visualize.mGraph.graph.getNode(newnode.id)
|
||||
if (!$.isEmptyObject(Visualize.mGraph.graph.nodes)) {
|
||||
Visualize.mGraph.graph.addNode(newnode)
|
||||
nodeOnViz = Visualize.mGraph.graph.getNode(newnode.id)
|
||||
topic.set('node', nodeOnViz, {silent: true})
|
||||
topic.updateNode() // links the topic and the mapping to the node
|
||||
|
||||
nodeOnViz.setData('dim', 1, 'start')
|
||||
nodeOnViz.setData('dim', 25, 'end')
|
||||
if (Metamaps.Visualize.type === 'RGraph') {
|
||||
if (Visualize.type === 'RGraph') {
|
||||
tempPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'))
|
||||
tempPos = tempPos.toPolar()
|
||||
nodeOnViz.setPos(tempPos, 'current')
|
||||
nodeOnViz.setPos(tempPos, 'start')
|
||||
nodeOnViz.setPos(tempPos, 'end')
|
||||
} else if (Metamaps.Visualize.type === 'ForceDirected') {
|
||||
} else if (Visualize.type === 'ForceDirected') {
|
||||
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'current')
|
||||
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'start')
|
||||
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'end')
|
||||
}
|
||||
if (Metamaps.Create.newTopic.addSynapse && permitCreateSynapseAfter) {
|
||||
Metamaps.Create.newSynapse.topic1id = Metamaps.tempNode.getData('topic').id
|
||||
if (Create.newTopic.addSynapse && permitCreateSynapseAfter) {
|
||||
Create.newSynapse.topic1id = JIT.tempNode.getData('topic').id
|
||||
|
||||
// position the form
|
||||
midpoint.x = Metamaps.tempNode.pos.getc().x + (nodeOnViz.pos.getc().x - Metamaps.tempNode.pos.getc().x) / 2
|
||||
midpoint.y = Metamaps.tempNode.pos.getc().y + (nodeOnViz.pos.getc().y - Metamaps.tempNode.pos.getc().y) / 2
|
||||
pixelPos = Metamaps.Util.coordsToPixels(midpoint)
|
||||
midpoint.x = JIT.tempNode.pos.getc().x + (nodeOnViz.pos.getc().x - JIT.tempNode.pos.getc().x) / 2
|
||||
midpoint.y = JIT.tempNode.pos.getc().y + (nodeOnViz.pos.getc().y - JIT.tempNode.pos.getc().y) / 2
|
||||
pixelPos = Util.coordsToPixels(midpoint)
|
||||
$('#new_synapse').css('left', pixelPos.x + 'px')
|
||||
$('#new_synapse').css('top', pixelPos.y + 'px')
|
||||
// show the form
|
||||
Metamaps.Create.newSynapse.open()
|
||||
Metamaps.Visualize.mGraph.fx.animate({
|
||||
Create.newSynapse.open()
|
||||
Visualize.mGraph.fx.animate({
|
||||
modes: ['node-property:dim'],
|
||||
duration: 500,
|
||||
onComplete: function () {
|
||||
Metamaps.tempNode = null
|
||||
Metamaps.tempNode2 = null
|
||||
Metamaps.tempInit = false
|
||||
JIT.tempNode = null
|
||||
JIT.tempNode2 = null
|
||||
JIT.tempInit = false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Metamaps.Visualize.mGraph.fx.plotNode(nodeOnViz, Metamaps.Visualize.mGraph.canvas)
|
||||
Metamaps.Visualize.mGraph.fx.animate({
|
||||
Visualize.mGraph.fx.plotNode(nodeOnViz, Visualize.mGraph.canvas)
|
||||
Visualize.mGraph.fx.animate({
|
||||
modes: ['node-property:dim'],
|
||||
duration: 500,
|
||||
onComplete: function () {}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Metamaps.Visualize.mGraph.loadJSON(newnode)
|
||||
nodeOnViz = Metamaps.Visualize.mGraph.graph.getNode(newnode.id)
|
||||
Visualize.mGraph.loadJSON(newnode)
|
||||
nodeOnViz = Visualize.mGraph.graph.getNode(newnode.id)
|
||||
topic.set('node', nodeOnViz, {silent: true})
|
||||
topic.updateNode() // links the topic and the mapping to the node
|
||||
|
||||
|
@ -256,8 +258,8 @@ Metamaps.Topic = {
|
|||
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'current')
|
||||
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'start')
|
||||
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'end')
|
||||
Metamaps.Visualize.mGraph.fx.plotNode(nodeOnViz, Metamaps.Visualize.mGraph.canvas)
|
||||
Metamaps.Visualize.mGraph.fx.animate({
|
||||
Visualize.mGraph.fx.plotNode(nodeOnViz, Visualize.mGraph.canvas)
|
||||
Visualize.mGraph.fx.animate({
|
||||
modes: ['node-property:dim'],
|
||||
duration: 500,
|
||||
onComplete: function () {}
|
||||
|
@ -270,14 +272,14 @@ Metamaps.Topic = {
|
|||
mappableid: mappingModel.get('mappable_id')
|
||||
}
|
||||
|
||||
$(document).trigger(Metamaps.JIT.events.newTopic, [newTopicData])
|
||||
$(document).trigger(JIT.events.newTopic, [newTopicData])
|
||||
// call a success callback if provided
|
||||
if (opts.success) {
|
||||
opts.success(topicModel)
|
||||
}
|
||||
}
|
||||
var topicSuccessCallback = function (topicModel, response) {
|
||||
if (Metamaps.Active.Map) {
|
||||
if (Active.Map) {
|
||||
mapping.save({ mappable_id: topicModel.id }, {
|
||||
success: function (model, response) {
|
||||
mappingSuccessCallback(model, response, topicModel)
|
||||
|
@ -288,12 +290,12 @@ Metamaps.Topic = {
|
|||
})
|
||||
}
|
||||
|
||||
if (Metamaps.Create.newTopic.addSynapse) {
|
||||
Metamaps.Create.newSynapse.topic2id = topicModel.id
|
||||
if (Create.newTopic.addSynapse) {
|
||||
Create.newSynapse.topic2id = topicModel.id
|
||||
}
|
||||
}
|
||||
|
||||
if (!Metamaps.Settings.sandbox && createNewInDB) {
|
||||
if (!Settings.sandbox && createNewInDB) {
|
||||
if (topic.isNew()) {
|
||||
topic.save(null, {
|
||||
success: topicSuccessCallback,
|
||||
|
@ -301,7 +303,7 @@ Metamaps.Topic = {
|
|||
console.log('error saving topic to database')
|
||||
}
|
||||
})
|
||||
} else if (!topic.isNew() && Metamaps.Active.Map) {
|
||||
} else if (!topic.isNew() && Active.Map) {
|
||||
mapping.save(null, {
|
||||
success: mappingSuccessCallback
|
||||
})
|
||||
|
@ -309,58 +311,58 @@ Metamaps.Topic = {
|
|||
}
|
||||
},
|
||||
createTopicLocally: function () {
|
||||
var self = Metamaps.Topic
|
||||
var self = Topic
|
||||
|
||||
if (Metamaps.Create.newTopic.name === '') {
|
||||
Metamaps.GlobalUI.notifyUser('Please enter a topic title...')
|
||||
if (Create.newTopic.name === '') {
|
||||
GlobalUI.notifyUser('Please enter a topic title...')
|
||||
return
|
||||
}
|
||||
|
||||
// hide the 'double-click to add a topic' message
|
||||
Metamaps.GlobalUI.hideDiv('#instructions')
|
||||
GlobalUI.hideDiv('#instructions')
|
||||
|
||||
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
|
||||
$(document).trigger(Map.events.editedByActiveMapper)
|
||||
|
||||
var metacode = Metamaps.Metacodes.get(Metamaps.Create.newTopic.metacode)
|
||||
var metacode = Metamaps.Metacodes.get(Create.newTopic.metacode)
|
||||
|
||||
var topic = new Metamaps.Backbone.Topic({
|
||||
name: Metamaps.Create.newTopic.name,
|
||||
name: Create.newTopic.name,
|
||||
metacode_id: metacode.id,
|
||||
defer_to_map_id: Metamaps.Active.Map.id
|
||||
defer_to_map_id: Active.Map.id
|
||||
})
|
||||
Metamaps.Topics.add(topic)
|
||||
|
||||
if (Metamaps.Create.newTopic.pinned) {
|
||||
var nextCoords = Metamaps.AutoLayout.getNextCoord()
|
||||
if (Create.newTopic.pinned) {
|
||||
var nextCoords = AutoLayout.getNextCoord()
|
||||
}
|
||||
var mapping = new Metamaps.Backbone.Mapping({
|
||||
xloc: nextCoords ? nextCoords.x : Metamaps.Create.newTopic.x,
|
||||
yloc: nextCoords ? nextCoords.y : Metamaps.Create.newTopic.y,
|
||||
xloc: nextCoords ? nextCoords.x : Create.newTopic.x,
|
||||
yloc: nextCoords ? nextCoords.y : Create.newTopic.y,
|
||||
mappable_id: topic.cid,
|
||||
mappable_type: 'Topic',
|
||||
})
|
||||
Metamaps.Mappings.add(mapping)
|
||||
|
||||
// these can't happen until the value is retrieved, which happens in the line above
|
||||
Metamaps.Create.newTopic.hide()
|
||||
Create.newTopic.hide()
|
||||
|
||||
self.renderTopic(mapping, topic, true, true) // this function also includes the creation of the topic in the database
|
||||
},
|
||||
getTopicFromAutocomplete: function (id) {
|
||||
var self = Metamaps.Topic
|
||||
var self = Topic
|
||||
|
||||
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
|
||||
$(document).trigger(Map.events.editedByActiveMapper)
|
||||
|
||||
Metamaps.Create.newTopic.hide()
|
||||
Create.newTopic.hide()
|
||||
|
||||
var topic = self.get(id)
|
||||
|
||||
if (Metamaps.Create.newTopic.pinned) {
|
||||
var nextCoords = Metamaps.AutoLayout.getNextCoord()
|
||||
if (Create.newTopic.pinned) {
|
||||
var nextCoords = AutoLayout.getNextCoord()
|
||||
}
|
||||
var mapping = new Metamaps.Backbone.Mapping({
|
||||
xloc: nextCoords ? nextCoords.x : Metamaps.Create.newTopic.x,
|
||||
yloc: nextCoords ? nextCoords.y : Metamaps.Create.newTopic.y,
|
||||
xloc: nextCoords ? nextCoords.x : Create.newTopic.x,
|
||||
yloc: nextCoords ? nextCoords.y : Create.newTopic.y,
|
||||
mappable_type: 'Topic',
|
||||
mappable_id: topic.id,
|
||||
})
|
||||
|
@ -369,13 +371,13 @@ Metamaps.Topic = {
|
|||
self.renderTopic(mapping, topic, true, true)
|
||||
},
|
||||
getTopicFromSearch: function (event, id) {
|
||||
var self = Metamaps.Topic
|
||||
var self = Topic
|
||||
|
||||
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
|
||||
$(document).trigger(Map.events.editedByActiveMapper)
|
||||
|
||||
var topic = self.get(id)
|
||||
|
||||
var nextCoords = Metamaps.AutoLayout.getNextCoord()
|
||||
var nextCoords = AutoLayout.getNextCoord()
|
||||
var mapping = new Metamaps.Backbone.Mapping({
|
||||
xloc: nextCoords.x,
|
||||
yloc: nextCoords.y,
|
||||
|
@ -386,10 +388,12 @@ Metamaps.Topic = {
|
|||
|
||||
self.renderTopic(mapping, topic, true, true)
|
||||
|
||||
Metamaps.GlobalUI.notifyUser('Topic was added to your map!')
|
||||
GlobalUI.notifyUser('Topic was added to your map!')
|
||||
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
return false
|
||||
}
|
||||
}; // end Metamaps.Topic
|
||||
}
|
||||
|
||||
export default Topic
|
|
@ -1,27 +1,28 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import Active from './Active'
|
||||
import GlobalUI from './GlobalUI'
|
||||
import Mapper from './Mapper'
|
||||
import Router from './Router'
|
||||
import Util from './Util'
|
||||
import Visualize from './Visualize'
|
||||
|
||||
/*
|
||||
* Metamaps.TopicCard.js
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.GlobalUI
|
||||
* - Metamaps.Mapper
|
||||
* - Metamaps.Metacodes
|
||||
* - Metamaps.Router
|
||||
* - Metamaps.Util
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
Metamaps.TopicCard = {
|
||||
const TopicCard = {
|
||||
openTopicCard: null, // stores the topic that's currently open
|
||||
authorizedToEdit: false, // stores boolean for edit permission for open topic card
|
||||
init: function () {
|
||||
var self = Metamaps.TopicCard
|
||||
var self = TopicCard
|
||||
|
||||
// initialize best_in_place editing
|
||||
$('.authenticated div.permission.canEdit .best_in_place').best_in_place()
|
||||
|
||||
Metamaps.TopicCard.generateShowcardHTML = Hogan.compile($('#topicCardTemplate').html())
|
||||
TopicCard.generateShowcardHTML = Hogan.compile($('#topicCardTemplate').html())
|
||||
|
||||
// initialize topic card draggability and resizability
|
||||
$('.showcard').draggable({
|
||||
|
@ -38,12 +39,12 @@ Metamaps.TopicCard = {
|
|||
* @param {$jit.Graph.Node} node
|
||||
*/
|
||||
showCard: function (node, opts) {
|
||||
var self = Metamaps.TopicCard
|
||||
|
||||
var self = TopicCard
|
||||
if (!opts) opts = {}
|
||||
var topic = node.getData('topic')
|
||||
|
||||
self.openTopicCard = topic
|
||||
self.authorizedToEdit = topic.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
self.authorizedToEdit = topic.authorizeToEdit(Active.Mapper)
|
||||
// populate the card that's about to show with the right topics data
|
||||
self.populateShowCard(topic)
|
||||
return $('.showcard').fadeIn('fast', function() {
|
||||
|
@ -53,14 +54,14 @@ Metamaps.TopicCard = {
|
|||
})
|
||||
},
|
||||
hideCard: function () {
|
||||
var self = Metamaps.TopicCard
|
||||
var self = TopicCard
|
||||
|
||||
$('.showcard').fadeOut('fast')
|
||||
self.openTopicCard = null
|
||||
self.authorizedToEdit = false
|
||||
},
|
||||
embedlyCardRendered: function (iframe) {
|
||||
var self = Metamaps.TopicCard
|
||||
var self = TopicCard
|
||||
|
||||
$('#embedlyLinkLoader').hide()
|
||||
|
||||
|
@ -77,7 +78,7 @@ Metamaps.TopicCard = {
|
|||
}
|
||||
},
|
||||
removeLink: function () {
|
||||
var self = Metamaps.TopicCard
|
||||
var self = TopicCard
|
||||
self.openTopicCard.save({
|
||||
link: null
|
||||
})
|
||||
|
@ -87,7 +88,7 @@ Metamaps.TopicCard = {
|
|||
$('.CardOnGraph').removeClass('hasAttachment')
|
||||
},
|
||||
bindShowCardListeners: function (topic) {
|
||||
var self = Metamaps.TopicCard
|
||||
var self = TopicCard
|
||||
var showCard = document.getElementById('showcard')
|
||||
|
||||
var authorized = self.authorizedToEdit
|
||||
|
@ -96,7 +97,7 @@ Metamaps.TopicCard = {
|
|||
var setMapperImage = function (mapper) {
|
||||
$('.contributorIcon').attr('src', mapper.get('image'))
|
||||
}
|
||||
Metamaps.Mapper.get(topic.get('user_id'), setMapperImage)
|
||||
Mapper.get(topic.get('user_id'), setMapperImage)
|
||||
|
||||
// starting embed.ly
|
||||
var resetFunc = function () {
|
||||
|
@ -179,24 +180,16 @@ Metamaps.TopicCard = {
|
|||
topic.save({
|
||||
metacode_id: metacode.id
|
||||
})
|
||||
Metamaps.Visualize.mGraph.plot()
|
||||
Visualize.mGraph.plot()
|
||||
$('.metacodeSelect').hide().removeClass('onRightEdge onBottomEdge')
|
||||
$('.metacodeTitle').hide()
|
||||
$('.showcard .icon').css('z-index', '1')
|
||||
}
|
||||
|
||||
var openMetacodeSelect = function (event) {
|
||||
var windowWidth
|
||||
var showcardLeft
|
||||
var TOPICCARD_WIDTH = 300
|
||||
var METACODESELECT_WIDTH = 404
|
||||
var distanceFromEdge
|
||||
|
||||
var MAX_METACODELIST_HEIGHT = 270
|
||||
var windowHeight
|
||||
var showcardTop
|
||||
var topicTitleHeight
|
||||
var distanceFromBottom
|
||||
|
||||
if (!selectingMetacode) {
|
||||
selectingMetacode = true
|
||||
|
@ -205,9 +198,9 @@ Metamaps.TopicCard = {
|
|||
// select is accessible onscreen, when opened
|
||||
// while topic card is close to the right
|
||||
// edge of the screen
|
||||
windowWidth = $(window).width()
|
||||
showcardLeft = parseInt($('.showcard').css('left'))
|
||||
distanceFromEdge = windowWidth - (showcardLeft + TOPICCARD_WIDTH)
|
||||
var windowWidth = $(window).width()
|
||||
var showcardLeft = parseInt($('.showcard').css('left'))
|
||||
var distanceFromEdge = windowWidth - (showcardLeft + TOPICCARD_WIDTH)
|
||||
if (distanceFromEdge < METACODESELECT_WIDTH) {
|
||||
$('.metacodeSelect').addClass('onRightEdge')
|
||||
}
|
||||
|
@ -216,11 +209,11 @@ Metamaps.TopicCard = {
|
|||
// select is accessible onscreen, when opened
|
||||
// while topic card is close to the bottom
|
||||
// edge of the screen
|
||||
windowHeight = $(window).height()
|
||||
showcardTop = parseInt($('.showcard').css('top'))
|
||||
topicTitleHeight = $('.showcard .title').height() + parseInt($('.showcard .title').css('padding-top')) + parseInt($('.showcard .title').css('padding-bottom'))
|
||||
heightOfSetList = $('.showcard .metacodeSelect').height()
|
||||
distanceFromBottom = windowHeight - (showcardTop + topicTitleHeight)
|
||||
var windowHeight = $(window).height()
|
||||
var showcardTop = parseInt($('.showcard').css('top'))
|
||||
var topicTitleHeight = $('.showcard .title').height() + parseInt($('.showcard .title').css('padding-top')) + parseInt($('.showcard .title').css('padding-bottom'))
|
||||
var heightOfSetList = $('.showcard .metacodeSelect').height()
|
||||
var distanceFromBottom = windowHeight - (showcardTop + topicTitleHeight)
|
||||
if (distanceFromBottom < MAX_METACODELIST_HEIGHT) {
|
||||
$('.metacodeSelect').addClass('onBottomEdge')
|
||||
}
|
||||
|
@ -265,7 +258,7 @@ Metamaps.TopicCard = {
|
|||
|
||||
// bind best_in_place ajax callbacks
|
||||
bipName.bind('ajax:success', function () {
|
||||
var name = Metamaps.Util.decodeEntities($(this).html())
|
||||
var name = Util.decodeEntities($(this).html())
|
||||
topic.set('name', name)
|
||||
topic.trigger('saved')
|
||||
})
|
||||
|
@ -313,7 +306,7 @@ Metamaps.TopicCard = {
|
|||
}
|
||||
// ability to change permission
|
||||
var selectingPermission = false
|
||||
if (topic.authorizePermissionChange(Metamaps.Active.Mapper)) {
|
||||
if (topic.authorizePermissionChange(Active.Mapper)) {
|
||||
$('.showcard .yourTopic .mapPerm').click(openPermissionSelect)
|
||||
$('.showcard').click(hidePermissionSelect)
|
||||
}
|
||||
|
@ -331,7 +324,7 @@ Metamaps.TopicCard = {
|
|||
$('.showcard .hoverTip').removeClass('hide')
|
||||
})
|
||||
|
||||
$('.mapCount .tip li a').click(Metamaps.Router.intercept)
|
||||
$('.mapCount .tip li a').click(Router.intercept)
|
||||
|
||||
var originalText = $('.showMore').html()
|
||||
$('.mapCount .tip .showMore').unbind().toggle(
|
||||
|
@ -349,13 +342,13 @@ Metamaps.TopicCard = {
|
|||
})
|
||||
},
|
||||
handleInvalidLink: function () {
|
||||
var self = Metamaps.TopicCard
|
||||
var self = TopicCard
|
||||
|
||||
self.removeLink()
|
||||
Metamaps.GlobalUI.notifyUser('Invalid link')
|
||||
GlobalUI.notifyUser('Invalid link')
|
||||
},
|
||||
populateShowCard: function (topic) {
|
||||
var self = Metamaps.TopicCard
|
||||
var self = TopicCard
|
||||
|
||||
var showCard = document.getElementById('showcard')
|
||||
|
||||
|
@ -364,11 +357,11 @@ Metamaps.TopicCard = {
|
|||
var topicForTemplate = self.buildObject(topic)
|
||||
var html = self.generateShowcardHTML.render(topicForTemplate)
|
||||
|
||||
if (topic.authorizeToEdit(Metamaps.Active.Mapper)) {
|
||||
if (topic.authorizeToEdit(Active.Mapper)) {
|
||||
var perm = document.createElement('div')
|
||||
|
||||
var string = 'permission canEdit'
|
||||
if (topic.authorizePermissionChange(Metamaps.Active.Mapper)) string += ' yourTopic'
|
||||
if (topic.authorizePermissionChange(Active.Mapper)) string += ' yourTopic'
|
||||
perm.className = string
|
||||
perm.innerHTML = html
|
||||
showCard.appendChild(perm)
|
||||
|
@ -379,16 +372,16 @@ Metamaps.TopicCard = {
|
|||
showCard.appendChild(perm)
|
||||
}
|
||||
|
||||
Metamaps.TopicCard.bindShowCardListeners(topic)
|
||||
TopicCard.bindShowCardListeners(topic)
|
||||
},
|
||||
generateShowcardHTML: null, // will be initialized into a Hogan template within init function
|
||||
// generateShowcardHTML
|
||||
buildObject: function (topic) {
|
||||
var self = Metamaps.TopicCard
|
||||
var self = TopicCard
|
||||
|
||||
var nodeValues = {}
|
||||
|
||||
var authorized = topic.authorizeToEdit(Metamaps.Active.Mapper)
|
||||
var authorized = topic.authorizeToEdit(Active.Mapper)
|
||||
|
||||
if (!authorized) {
|
||||
} else {
|
||||
|
@ -421,18 +414,18 @@ Metamaps.TopicCard = {
|
|||
var inmapsLinks = topic.get('inmapsLinks') || []
|
||||
nodeValues.inmaps = ''
|
||||
if (inmapsAr.length < 6) {
|
||||
for (i = 0; i < inmapsAr.length; i++) {
|
||||
for (let i = 0; i < inmapsAr.length; i++) {
|
||||
var url = '/maps/' + inmapsLinks[i]
|
||||
nodeValues.inmaps += '<li><a href="' + url + '">' + inmapsAr[i] + '</a></li>'
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
var url = '/maps/' + inmapsLinks[i]
|
||||
nodeValues.inmaps += '<li><a href="' + url + '">' + inmapsAr[i] + '</a></li>'
|
||||
}
|
||||
extra = inmapsAr.length - 5
|
||||
nodeValues.inmaps += '<li><span class="showMore">See ' + extra + ' more...</span></li>'
|
||||
for (i = 5; i < inmapsAr.length; i++) {
|
||||
for (let i = 5; i < inmapsAr.length; i++) {
|
||||
var url = '/maps/' + inmapsLinks[i]
|
||||
nodeValues.inmaps += '<li class="hideExtra extraText"><a href="' + url + '">' + inmapsAr[i] + '</a></li>'
|
||||
}
|
||||
|
@ -455,4 +448,6 @@ Metamaps.TopicCard = {
|
|||
nodeValues.desc = (topic.get('desc') == '' && authorized) ? desc_nil : topic.get('desc')
|
||||
return nodeValues
|
||||
}
|
||||
}; // end Metamaps.TopicCard
|
||||
}
|
||||
|
||||
export default TopicCard
|
|
@ -1,13 +1,6 @@
|
|||
/* global Metamaps */
|
||||
import Visualize from './Visualize'
|
||||
|
||||
/*
|
||||
* Metamaps.Util.js
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
|
||||
Metamaps.Util = {
|
||||
const Util = {
|
||||
// helper function to determine how many lines are needed
|
||||
// Line Splitter Function
|
||||
// copyright Stephen Chapman, 19th April 2006
|
||||
|
@ -45,8 +38,8 @@ Metamaps.Util = {
|
|||
return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2))
|
||||
},
|
||||
coordsToPixels: function (coords) {
|
||||
if (Metamaps.Visualize.mGraph) {
|
||||
var canvas = Metamaps.Visualize.mGraph.canvas,
|
||||
if (Visualize.mGraph) {
|
||||
var canvas = Visualize.mGraph.canvas,
|
||||
s = canvas.getSize(),
|
||||
p = canvas.getPos(),
|
||||
ox = canvas.translateOffsetX,
|
||||
|
@ -67,8 +60,8 @@ Metamaps.Util = {
|
|||
},
|
||||
pixelsToCoords: function (pixels) {
|
||||
var coords
|
||||
if (Metamaps.Visualize.mGraph) {
|
||||
var canvas = Metamaps.Visualize.mGraph.canvas,
|
||||
if (Visualize.mGraph) {
|
||||
var canvas = Visualize.mGraph.canvas,
|
||||
s = canvas.getSize(),
|
||||
p = canvas.getPos(),
|
||||
ox = canvas.translateOffsetX,
|
||||
|
@ -91,7 +84,7 @@ Metamaps.Util = {
|
|||
var r = (Math.round(Math.random() * 127) + 127).toString(16)
|
||||
var g = (Math.round(Math.random() * 127) + 127).toString(16)
|
||||
var b = (Math.round(Math.random() * 127) + 127).toString(16)
|
||||
return Metamaps.Util.colorLuminance('#' + r + g + b, -0.4)
|
||||
return Util.colorLuminance('#' + r + g + b, -0.4)
|
||||
},
|
||||
// darkens a hex value by 'lum' percentage
|
||||
colorLuminance: function (hex, lum) {
|
||||
|
@ -127,4 +120,6 @@ Metamaps.Util = {
|
|||
checkURLisYoutubeVideo: function (url) {
|
||||
return (url.match(/^https?:\/\/(?:www\.)?youtube.com\/watch\?(?=[^?]*v=\w+)(?:[^\s?]+)?$/) != null)
|
||||
}
|
||||
}; // end Metamaps.Util
|
||||
}
|
||||
|
||||
export default Util
|
343
frontend/src/Metamaps/Views/ChatView.js
Normal file
343
frontend/src/Metamaps/Views/ChatView.js
Normal file
|
@ -0,0 +1,343 @@
|
|||
/* global $ */
|
||||
|
||||
import Backbone from 'backbone'
|
||||
import Autolinker from 'autolinker'
|
||||
// TODO is this line good or bad
|
||||
// Backbone.$ = window.$
|
||||
|
||||
const linker = new Autolinker({ newWindow: true, truncate: 50, email: false, phone: false, twitter: false });
|
||||
|
||||
var Private = {
|
||||
messageHTML: "<div class='chat-message'>" +
|
||||
"<div class='chat-message-user'><img src='{{ user_image }}' title='{{user_name }}'/></div>" +
|
||||
"<div class='chat-message-text'>{{ message }}</div>" +
|
||||
"<div class='chat-message-time'>{{ timestamp }}</div>" +
|
||||
"<div class='clearfloat'></div>" +
|
||||
"</div>",
|
||||
participantHTML: "<div class='participant participant-{{ id }} {{ selfClass }}'>" +
|
||||
"<div class='chat-participant-image'><img src='{{ image }}' style='border: 2px solid {{ color }};' /></div>" +
|
||||
"<div class='chat-participant-name'>{{ username }} {{ selfName }}</div>" +
|
||||
"<button type='button' class='button chat-participant-invite-call' onclick='Metamaps.Realtime.inviteACall({{ id}});'></button>" +
|
||||
"<button type='button' class='button chat-participant-invite-join' onclick='Metamaps.Realtime.inviteToJoin({{ id}});'></button>" +
|
||||
"<span class='chat-participant-participating'><div class='green-dot'></div></span>" +
|
||||
"<div class='clearfloat'></div>" +
|
||||
"</div>",
|
||||
templates: function() {
|
||||
_.templateSettings = {
|
||||
interpolate: /\{\{(.+?)\}\}/g
|
||||
};
|
||||
this.messageTemplate = _.template(Private.messageHTML);
|
||||
|
||||
this.participantTemplate = _.template(Private.participantHTML);
|
||||
},
|
||||
createElements: function() {
|
||||
this.$unread = $('<div class="chat-unread"></div>');
|
||||
this.$button = $('<div class="chat-button"><div class="tooltips">Chat</div></div>');
|
||||
this.$messageInput = $('<textarea placeholder="Send a message..." class="chat-input"></textarea>');
|
||||
this.$juntoHeader = $('<div class="junto-header">PARTICIPANTS</div>');
|
||||
this.$videoToggle = $('<div class="video-toggle"></div>');
|
||||
this.$cursorToggle = $('<div class="cursor-toggle"></div>');
|
||||
this.$participants = $('<div class="participants"></div>');
|
||||
this.$conversationInProgress = $('<div class="conversation-live">LIVE <span class="call-action leave" onclick="Metamaps.Realtime.leaveCall();">LEAVE</span><span class="call-action join" onclick="Metamaps.Realtime.joinCall();">JOIN</span></div>');
|
||||
this.$chatHeader = $('<div class="chat-header">CHAT</div>');
|
||||
this.$soundToggle = $('<div class="sound-toggle"></div>');
|
||||
this.$messages = $('<div class="chat-messages"></div>');
|
||||
this.$container = $('<div class="chat-box"></div>');
|
||||
},
|
||||
attachElements: function() {
|
||||
this.$button.append(this.$unread);
|
||||
|
||||
this.$juntoHeader.append(this.$videoToggle);
|
||||
this.$juntoHeader.append(this.$cursorToggle);
|
||||
|
||||
this.$chatHeader.append(this.$soundToggle);
|
||||
|
||||
this.$participants.append(this.$conversationInProgress);
|
||||
|
||||
this.$container.append(this.$juntoHeader);
|
||||
this.$container.append(this.$participants);
|
||||
this.$container.append(this.$chatHeader);
|
||||
this.$container.append(this.$button);
|
||||
this.$container.append(this.$messages);
|
||||
this.$container.append(this.$messageInput);
|
||||
},
|
||||
addEventListeners: function() {
|
||||
var self = this;
|
||||
|
||||
this.participants.on('add', function (participant) {
|
||||
Private.addParticipant.call(self, participant);
|
||||
});
|
||||
|
||||
this.participants.on('remove', function (participant) {
|
||||
Private.removeParticipant.call(self, participant);
|
||||
});
|
||||
|
||||
this.$button.on('click', function () {
|
||||
Handlers.buttonClick.call(self);
|
||||
});
|
||||
this.$videoToggle.on('click', function () {
|
||||
Handlers.videoToggleClick.call(self);
|
||||
});
|
||||
this.$cursorToggle.on('click', function () {
|
||||
Handlers.cursorToggleClick.call(self);
|
||||
});
|
||||
this.$soundToggle.on('click', function () {
|
||||
Handlers.soundToggleClick.call(self);
|
||||
});
|
||||
this.$messageInput.on('keyup', function (event) {
|
||||
Handlers.keyUp.call(self, event);
|
||||
});
|
||||
this.$messageInput.on('focus', function () {
|
||||
Handlers.inputFocus.call(self);
|
||||
});
|
||||
this.$messageInput.on('blur', function () {
|
||||
Handlers.inputBlur.call(self);
|
||||
});
|
||||
},
|
||||
initializeSounds: function() {
|
||||
this.sound = new Howl({
|
||||
urls: [Metamaps.Erb['sounds/MM_sounds.mp3'], Metamaps.Erb['sounds/MM_sounds.ogg']],
|
||||
sprite: {
|
||||
joinmap: [0, 561],
|
||||
leavemap: [1000, 592],
|
||||
receivechat: [2000, 318],
|
||||
sendchat: [3000, 296],
|
||||
sessioninvite: [4000, 5393, true]
|
||||
}
|
||||
});
|
||||
},
|
||||
incrementUnread: function() {
|
||||
this.unreadMessages++;
|
||||
this.$unread.html(this.unreadMessages);
|
||||
this.$unread.show();
|
||||
},
|
||||
addMessage: function(message, isInitial, wasMe) {
|
||||
|
||||
if (!this.isOpen && !isInitial) Private.incrementUnread.call(this);
|
||||
|
||||
function addZero(i) {
|
||||
if (i < 10) {
|
||||
i = "0" + i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
var m = _.clone(message.attributes);
|
||||
|
||||
var today = new Date();
|
||||
m.timestamp = new Date(m.created_at);
|
||||
|
||||
var date = (m.timestamp.getMonth() + 1) + '/' + m.timestamp.getDate();
|
||||
date += " " + addZero(m.timestamp.getHours()) + ":" + addZero(m.timestamp.getMinutes());
|
||||
m.timestamp = date;
|
||||
m.image = m.user_image || 'http://www.hotpepper.ca/wp-content/uploads/2014/11/default_profile_1_200x200.png'; // TODO: remove
|
||||
m.message = linker.link(m.message);
|
||||
var $html = $(this.messageTemplate(m));
|
||||
this.$messages.append($html);
|
||||
if (!isInitial) this.scrollMessages(200);
|
||||
|
||||
if (!wasMe && !isInitial && this.alertSound) this.sound.play('receivechat');
|
||||
},
|
||||
initialMessages: function() {
|
||||
var messages = this.messages.models;
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
Private.addMessage.call(this, messages[i], true);
|
||||
}
|
||||
},
|
||||
handleInputMessage: function() {
|
||||
var message = {
|
||||
message: this.$messageInput.val(),
|
||||
};
|
||||
this.$messageInput.val('');
|
||||
$(document).trigger(ChatView.events.message + '-' + this.room, [message]);
|
||||
},
|
||||
addParticipant: function(participant) {
|
||||
var p = _.clone(participant.attributes);
|
||||
if (p.self) {
|
||||
p.selfClass = 'is-self';
|
||||
p.selfName = '(me)';
|
||||
} else {
|
||||
p.selfClass = '';
|
||||
p.selfName = '';
|
||||
}
|
||||
var html = this.participantTemplate(p);
|
||||
this.$participants.append(html);
|
||||
},
|
||||
removeParticipant: function(participant) {
|
||||
this.$container.find('.participant-' + participant.get('id')).remove();
|
||||
}
|
||||
};
|
||||
|
||||
var Handlers = {
|
||||
buttonClick: function() {
|
||||
if (this.isOpen) this.close();
|
||||
else if (!this.isOpen) this.open();
|
||||
},
|
||||
videoToggleClick: function() {
|
||||
this.$videoToggle.toggleClass('active');
|
||||
this.videosShowing = !this.videosShowing;
|
||||
$(document).trigger(this.videosShowing ? ChatView.events.videosOn : ChatView.events.videosOff);
|
||||
},
|
||||
cursorToggleClick: function() {
|
||||
this.$cursorToggle.toggleClass('active');
|
||||
this.cursorsShowing = !this.cursorsShowing;
|
||||
$(document).trigger(this.cursorsShowing ? ChatView.events.cursorsOn : ChatView.events.cursorsOff);
|
||||
},
|
||||
soundToggleClick: function() {
|
||||
this.alertSound = !this.alertSound;
|
||||
this.$soundToggle.toggleClass('active');
|
||||
},
|
||||
keyUp: function(event) {
|
||||
switch(event.which) {
|
||||
case 13: // enter
|
||||
Private.handleInputMessage.call(this);
|
||||
break;
|
||||
}
|
||||
},
|
||||
inputFocus: function() {
|
||||
$(document).trigger(ChatView.events.inputFocus);
|
||||
},
|
||||
inputBlur: function() {
|
||||
$(document).trigger(ChatView.events.inputBlur);
|
||||
}
|
||||
};
|
||||
|
||||
const ChatView = function(messages, mapper, room) {
|
||||
var self = this;
|
||||
|
||||
this.room = room;
|
||||
this.mapper = mapper;
|
||||
this.messages = messages; // backbone collection
|
||||
|
||||
this.isOpen = false;
|
||||
this.alertSound = true; // whether to play sounds on arrival of new messages or not
|
||||
this.cursorsShowing = true;
|
||||
this.videosShowing = true;
|
||||
this.unreadMessages = 0;
|
||||
this.participants = new Backbone.Collection();
|
||||
|
||||
Private.templates.call(this);
|
||||
Private.createElements.call(this);
|
||||
Private.attachElements.call(this);
|
||||
Private.addEventListeners.call(this);
|
||||
Private.initialMessages.call(this);
|
||||
Private.initializeSounds.call(this);
|
||||
this.$container.css({
|
||||
right: '-300px'
|
||||
});
|
||||
};
|
||||
|
||||
ChatView.prototype.conversationInProgress = function (participating) {
|
||||
this.$conversationInProgress.show();
|
||||
this.$participants.addClass('is-live');
|
||||
if (participating) this.$participants.addClass('is-participating');
|
||||
this.$button.addClass('active');
|
||||
|
||||
// hide invite to call buttons
|
||||
}
|
||||
|
||||
ChatView.prototype.conversationEnded = function () {
|
||||
this.$conversationInProgress.hide();
|
||||
this.$participants.removeClass('is-live');
|
||||
this.$participants.removeClass('is-participating');
|
||||
this.$button.removeClass('active');
|
||||
this.$participants.find('.participant').removeClass('active');
|
||||
this.$participants.find('.participant').removeClass('pending');
|
||||
}
|
||||
|
||||
ChatView.prototype.leaveConversation = function () {
|
||||
this.$participants.removeClass('is-participating');
|
||||
}
|
||||
|
||||
ChatView.prototype.mapperJoinedCall = function (id) {
|
||||
this.$participants.find('.participant-' + id).addClass('active');
|
||||
}
|
||||
|
||||
ChatView.prototype.mapperLeftCall = function (id) {
|
||||
this.$participants.find('.participant-' + id).removeClass('active');
|
||||
}
|
||||
|
||||
ChatView.prototype.invitationPending = function (id) {
|
||||
this.$participants.find('.participant-' + id).addClass('pending');
|
||||
}
|
||||
|
||||
ChatView.prototype.invitationAnswered = function (id) {
|
||||
this.$participants.find('.participant-' + id).removeClass('pending');
|
||||
}
|
||||
|
||||
ChatView.prototype.addParticipant = function (participant) {
|
||||
this.participants.add(participant);
|
||||
}
|
||||
|
||||
ChatView.prototype.removeParticipant = function (username) {
|
||||
var p = this.participants.find(function (p) { return p.get('username') === username; });
|
||||
if (p) {
|
||||
this.participants.remove(p);
|
||||
}
|
||||
}
|
||||
|
||||
ChatView.prototype.removeParticipants = function () {
|
||||
this.participants.remove(this.participants.models);
|
||||
}
|
||||
|
||||
ChatView.prototype.open = function () {
|
||||
this.$container.css({
|
||||
right: '0'
|
||||
});
|
||||
this.$messageInput.focus();
|
||||
this.isOpen = true;
|
||||
this.unreadMessages = 0;
|
||||
this.$unread.hide();
|
||||
this.scrollMessages(0);
|
||||
$(document).trigger(ChatView.events.openTray);
|
||||
}
|
||||
|
||||
ChatView.prototype.addMessage = function(message, isInitial, wasMe) {
|
||||
this.messages.add(message);
|
||||
Private.addMessage.call(this, message, isInitial, wasMe);
|
||||
}
|
||||
|
||||
ChatView.prototype.scrollMessages = function(duration) {
|
||||
duration = duration || 0;
|
||||
|
||||
this.$messages.animate({
|
||||
scrollTop: this.$messages[0].scrollHeight
|
||||
}, duration);
|
||||
}
|
||||
|
||||
ChatView.prototype.clearMessages = function () {
|
||||
this.unreadMessages = 0;
|
||||
this.$unread.hide();
|
||||
this.$messages.empty();
|
||||
}
|
||||
|
||||
ChatView.prototype.close = function () {
|
||||
this.$container.css({
|
||||
right: '-300px'
|
||||
});
|
||||
this.$messageInput.blur();
|
||||
this.isOpen = false;
|
||||
$(document).trigger(ChatView.events.closeTray);
|
||||
}
|
||||
|
||||
ChatView.prototype.remove = function () {
|
||||
this.$button.off();
|
||||
this.$container.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @static
|
||||
*/
|
||||
ChatView.events = {
|
||||
message: 'ChatView:message',
|
||||
openTray: 'ChatView:openTray',
|
||||
closeTray: 'ChatView:closeTray',
|
||||
inputFocus: 'ChatView:inputFocus',
|
||||
inputBlur: 'ChatView:inputBlur',
|
||||
cursorsOff: 'ChatView:cursorsOff',
|
||||
cursorsOn: 'ChatView:cursorsOn',
|
||||
videosOff: 'ChatView:videosOff',
|
||||
videosOn: 'ChatView:videosOn'
|
||||
};
|
||||
|
||||
export default ChatView
|
88
frontend/src/Metamaps/Views/ExploreMaps.js
Normal file
88
frontend/src/Metamaps/Views/ExploreMaps.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom' // TODO ensure this isn't a double import
|
||||
|
||||
import Active from '../Active'
|
||||
import ReactComponents from '../ReactComponents'
|
||||
|
||||
/*
|
||||
* - Metamaps.Loading
|
||||
*/
|
||||
|
||||
const ExploreMaps = {
|
||||
setCollection: function (collection) {
|
||||
var self = ExploreMaps
|
||||
|
||||
if (self.collection) {
|
||||
self.collection.off('add', self.render)
|
||||
self.collection.off('successOnFetch', self.handleSuccess)
|
||||
self.collection.off('errorOnFetch', self.handleError)
|
||||
}
|
||||
self.collection = collection
|
||||
self.collection.on('add', self.render)
|
||||
self.collection.on('successOnFetch', self.handleSuccess)
|
||||
self.collection.on('errorOnFetch', self.handleError)
|
||||
},
|
||||
render: function (mapperObj, cb) {
|
||||
var self = ExploreMaps
|
||||
|
||||
if (typeof mapperObj === 'function') {
|
||||
cb = mapperObj
|
||||
mapperObj = null
|
||||
}
|
||||
|
||||
var exploreObj = {
|
||||
currentUser: Active.Mapper,
|
||||
section: self.collection.id,
|
||||
displayStyle: 'grid',
|
||||
maps: self.collection,
|
||||
moreToLoad: self.collection.page != 'loadedAll',
|
||||
user: mapperObj,
|
||||
loadMore: self.loadMore
|
||||
}
|
||||
ReactDOM.render(
|
||||
React.createElement(ReactComponents.Maps, exploreObj),
|
||||
document.getElementById('explore')
|
||||
)
|
||||
|
||||
if (cb) cb()
|
||||
Metamaps.Loading.hide()
|
||||
},
|
||||
loadMore: function () {
|
||||
var self = ExploreMaps
|
||||
|
||||
if (self.collection.page != "loadedAll") {
|
||||
self.collection.getMaps()
|
||||
}
|
||||
else self.render()
|
||||
},
|
||||
handleSuccess: function (cb) {
|
||||
var self = ExploreMaps
|
||||
|
||||
if (self.collection && self.collection.id === 'mapper') {
|
||||
self.fetchUserThenRender(cb)
|
||||
} else {
|
||||
self.render(cb)
|
||||
}
|
||||
},
|
||||
handleError: function () {
|
||||
console.log('error loading maps!') // TODO
|
||||
},
|
||||
fetchUserThenRender: function (cb) {
|
||||
var self = ExploreMaps
|
||||
|
||||
// first load the mapper object and then call the render function
|
||||
$.ajax({
|
||||
url: '/users/' + self.collection.mapperId + '/details.json',
|
||||
success: function (response) {
|
||||
self.render(response, cb)
|
||||
},
|
||||
error: function () {
|
||||
self.render(cb)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default ExploreMaps
|
204
frontend/src/Metamaps/Views/Room.js
Normal file
204
frontend/src/Metamaps/Views/Room.js
Normal file
|
@ -0,0 +1,204 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import Backbone from 'backbone'
|
||||
// TODO is this line good or bad
|
||||
// Backbone.$ = window.$
|
||||
|
||||
import Active from '../Active'
|
||||
import Realtime from '../Realtime'
|
||||
|
||||
import ChatView from './ChatView'
|
||||
import VideoView from './VideoView'
|
||||
|
||||
/*
|
||||
* Dependencies:
|
||||
* Metamaps.Backbone
|
||||
*/
|
||||
|
||||
const Room = function(opts) {
|
||||
var self = this
|
||||
|
||||
this.isActiveRoom = false
|
||||
this.socket = opts.socket
|
||||
this.webrtc = opts.webrtc
|
||||
//this.roomRef = opts.firebase
|
||||
this.room = opts.room
|
||||
this.config = opts.config
|
||||
this.peopleCount = 0
|
||||
|
||||
this.$myVideo = opts.$video
|
||||
this.myVideo = opts.myVideoView
|
||||
|
||||
this.messages = new Backbone.Collection()
|
||||
this.currentMapper = new Backbone.Model({ name: opts.username, image: opts.image })
|
||||
this.chat = new ChatView(this.messages, this.currentMapper, this.room)
|
||||
|
||||
this.videos = {}
|
||||
|
||||
this.init()
|
||||
}
|
||||
|
||||
Room.prototype.join = function(cb) {
|
||||
this.isActiveRoom = true
|
||||
this.webrtc.joinRoom(this.room, cb)
|
||||
this.chat.conversationInProgress(true) // true indicates participation
|
||||
}
|
||||
|
||||
Room.prototype.conversationInProgress = function() {
|
||||
this.chat.conversationInProgress(false) // false indicates not participating
|
||||
}
|
||||
|
||||
Room.prototype.conversationEnding = function() {
|
||||
this.chat.conversationEnded()
|
||||
}
|
||||
|
||||
Room.prototype.leaveVideoOnly = function() {
|
||||
this.chat.leaveConversation() // the conversation will carry on without you
|
||||
for (var id in this.videos) {
|
||||
this.removeVideo(id)
|
||||
}
|
||||
this.isActiveRoom = false
|
||||
this.webrtc.leaveRoom()
|
||||
}
|
||||
|
||||
Room.prototype.leave = function() {
|
||||
for (var id in this.videos) {
|
||||
this.removeVideo(id)
|
||||
}
|
||||
this.isActiveRoom = false
|
||||
this.webrtc.leaveRoom()
|
||||
this.chat.conversationEnded()
|
||||
this.chat.removeParticipants()
|
||||
this.chat.clearMessages()
|
||||
this.messages.reset()
|
||||
}
|
||||
|
||||
Room.prototype.setPeopleCount = function(count) {
|
||||
this.peopleCount = count
|
||||
}
|
||||
|
||||
Room.prototype.init = function () {
|
||||
var self = this
|
||||
|
||||
$(document).on(VideoView.events.audioControlClick, function (event, videoView) {
|
||||
if (!videoView.audioStatus) self.webrtc.mute()
|
||||
else if (videoView.audioStatus) self.webrtc.unmute()
|
||||
})
|
||||
$(document).on(VideoView.events.videoControlClick, function (event, videoView) {
|
||||
if (!videoView.videoStatus) self.webrtc.pauseVideo()
|
||||
else if (videoView.videoStatus) self.webrtc.resumeVideo()
|
||||
})
|
||||
|
||||
this.webrtc.webrtc.off('peerStreamAdded')
|
||||
this.webrtc.webrtc.off('peerStreamRemoved')
|
||||
this.webrtc.on('peerStreamAdded', function (peer) {
|
||||
var mapper = Realtime.mappersOnMap[peer.nick]
|
||||
peer.avatar = mapper.image
|
||||
peer.username = mapper.name
|
||||
if (self.isActiveRoom) {
|
||||
self.addVideo(peer)
|
||||
}
|
||||
})
|
||||
|
||||
this.webrtc.on('peerStreamRemoved', function (peer) {
|
||||
if (self.isActiveRoom) {
|
||||
self.removeVideo(peer)
|
||||
}
|
||||
})
|
||||
|
||||
this.webrtc.on('mute', function (data) {
|
||||
var v = self.videos[data.id]
|
||||
if (!v) return
|
||||
|
||||
if (data.name === 'audio') {
|
||||
v.audioStatus = false
|
||||
}
|
||||
else if (data.name === 'video') {
|
||||
v.videoStatus = false
|
||||
v.$avatar.show()
|
||||
}
|
||||
if (!v.audioStatus && !v.videoStatus) v.$container.hide()
|
||||
})
|
||||
this.webrtc.on('unmute', function (data) {
|
||||
var v = self.videos[data.id]
|
||||
if (!v) return
|
||||
|
||||
if (data.name === 'audio') {
|
||||
v.audioStatus = true
|
||||
}
|
||||
else if (data.name === 'video') {
|
||||
v.videoStatus = true
|
||||
v.$avatar.hide()
|
||||
}
|
||||
v.$container.show()
|
||||
})
|
||||
|
||||
var sendChatMessage = function (event, data) {
|
||||
self.sendChatMessage(data)
|
||||
}
|
||||
$(document).on(ChatView.events.message + '-' + this.room, sendChatMessage)
|
||||
}
|
||||
|
||||
Room.prototype.videoAdded = function (callback) {
|
||||
this._videoAdded = callback
|
||||
}
|
||||
|
||||
Room.prototype.addVideo = function (peer) {
|
||||
var
|
||||
id = this.webrtc.getDomId(peer),
|
||||
video = attachMediaStream(peer.stream)
|
||||
|
||||
var
|
||||
v = new VideoView(video, null, id, false, { DOUBLE_CLICK_TOLERANCE: 200, avatar: peer.avatar, username: peer.username })
|
||||
|
||||
this.videos[peer.id] = v
|
||||
if (this._videoAdded) this._videoAdded(v, peer.nick)
|
||||
}
|
||||
|
||||
Room.prototype.removeVideo = function (peer) {
|
||||
var id = typeof peer == 'string' ? peer : peer.id
|
||||
if (this.videos[id]) {
|
||||
this.videos[id].remove()
|
||||
delete this.videos[id]
|
||||
}
|
||||
}
|
||||
|
||||
Room.prototype.sendChatMessage = function (data) {
|
||||
var self = this
|
||||
//this.roomRef.child('messages').push(data)
|
||||
if (self.chat.alertSound) self.chat.sound.play('sendchat')
|
||||
var m = new Metamaps.Backbone.Message({
|
||||
message: data.message,
|
||||
resource_id: Active.Map.id,
|
||||
resource_type: "Map"
|
||||
})
|
||||
m.save(null, {
|
||||
success: function (model, response) {
|
||||
self.addMessages(new Metamaps.Backbone.MessageCollection(model), false, true)
|
||||
$(document).trigger(Room.events.newMessage, [model])
|
||||
},
|
||||
error: function (model, response) {
|
||||
console.log('error!', response)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// they should be instantiated as backbone models before they get
|
||||
// passed to this function
|
||||
Room.prototype.addMessages = function (messages, isInitial, wasMe) {
|
||||
var self = this
|
||||
|
||||
messages.models.forEach(function (message) {
|
||||
self.chat.addMessage(message, isInitial, wasMe)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @static
|
||||
*/
|
||||
Room.events = {
|
||||
newMessage: "Room:newMessage"
|
||||
}
|
||||
|
||||
export default Room
|
202
frontend/src/Metamaps/Views/VideoView.js
Normal file
202
frontend/src/Metamaps/Views/VideoView.js
Normal file
|
@ -0,0 +1,202 @@
|
|||
/* global $ */
|
||||
|
||||
var Private = {
|
||||
addControls: function() {
|
||||
var self = this;
|
||||
|
||||
this.$audioControl = $('<div class="video-audio"></div>');
|
||||
this.$videoControl = $('<div class="video-video"></div>');
|
||||
|
||||
this.$audioControl.on('click', function () {
|
||||
Handlers.audioControlClick.call(self);
|
||||
});
|
||||
|
||||
this.$videoControl.on('click', function () {
|
||||
Handlers.videoControlClick.call(self);
|
||||
});
|
||||
|
||||
this.$container.append(this.$audioControl);
|
||||
this.$container.append(this.$videoControl);
|
||||
},
|
||||
cancelClick: function() {
|
||||
this.mouseIsDown = false;
|
||||
|
||||
if (this.hasMoved) {
|
||||
|
||||
}
|
||||
|
||||
$(document).trigger(VideoView.events.dragEnd);
|
||||
}
|
||||
};
|
||||
|
||||
var Handlers = {
|
||||
mousedown: function(event) {
|
||||
this.mouseIsDown = true;
|
||||
this.hasMoved = false;
|
||||
this.mouseMoveStart = {
|
||||
x: event.pageX,
|
||||
y: event.pageY
|
||||
};
|
||||
this.posStart = {
|
||||
x: parseInt(this.$container.css('left'), '10'),
|
||||
y: parseInt(this.$container.css('top'), '10')
|
||||
}
|
||||
|
||||
$(document).trigger(VideoView.events.mousedown);
|
||||
},
|
||||
mouseup: function(event) {
|
||||
$(document).trigger(VideoView.events.mouseup, [this]);
|
||||
|
||||
var storedTime = this.lastClick;
|
||||
var now = Date.now();
|
||||
this.lastClick = now;
|
||||
|
||||
if (now - storedTime < this.config.DOUBLE_CLICK_TOLERANCE) {
|
||||
$(document).trigger(VideoView.events.doubleClick, [this]);
|
||||
}
|
||||
},
|
||||
mousemove: function(event) {
|
||||
var
|
||||
diffX,
|
||||
diffY,
|
||||
newX,
|
||||
newY;
|
||||
|
||||
if (this.$parent && this.mouseIsDown) {
|
||||
this.manuallyPositioned = true;
|
||||
this.hasMoved = true;
|
||||
diffX = event.pageX - this.mouseMoveStart.x;
|
||||
diffY = this.mouseMoveStart.y - event.pageY;
|
||||
newX = this.posStart.x + diffX;
|
||||
newY = this.posStart.y - diffY;
|
||||
this.$container.css({
|
||||
top: newY,
|
||||
left: newX
|
||||
});
|
||||
}
|
||||
},
|
||||
audioControlClick: function() {
|
||||
if (this.audioStatus) {
|
||||
this.audioOff();
|
||||
} else {
|
||||
this.audioOn();
|
||||
}
|
||||
$(document).trigger(VideoView.events.audioControlClick, [this]);
|
||||
},
|
||||
videoControlClick: function() {
|
||||
if (this.videoStatus) {
|
||||
this.videoOff();
|
||||
} else {
|
||||
this.videoOn();
|
||||
}
|
||||
$(document).trigger(VideoView.events.videoControlClick, [this]);
|
||||
},
|
||||
};
|
||||
|
||||
var VideoView = function(video, $parent, id, isMyself, config) {
|
||||
var self = this;
|
||||
|
||||
this.$parent = $parent; // mapView
|
||||
|
||||
this.video = video;
|
||||
this.id = id;
|
||||
|
||||
this.config = config;
|
||||
|
||||
this.mouseIsDown = false;
|
||||
this.mouseDownOffset = { x: 0, y: 0 };
|
||||
this.lastClick = null;
|
||||
this.hasMoved = false;
|
||||
|
||||
this.audioStatus = true;
|
||||
this.videoStatus = true;
|
||||
|
||||
this.$container = $('<div></div>');
|
||||
this.$container.addClass('collaborator-video' + (isMyself ? ' my-video' : ''));
|
||||
this.$container.attr('id', 'container_' + id);
|
||||
|
||||
|
||||
var $vidContainer = $('<div></div>');
|
||||
$vidContainer.addClass('video-cutoff');
|
||||
$vidContainer.append(this.video);
|
||||
|
||||
this.avatar = config.avatar;
|
||||
this.$avatar = $('<img draggable="false" class="collaborator-video-avatar" src="' + config.avatar + '" width="150" height="150" />');
|
||||
$vidContainer.append(this.$avatar);
|
||||
|
||||
this.$container.append($vidContainer);
|
||||
|
||||
this.$container.on('mousedown', function (event) {
|
||||
Handlers.mousedown.call(self, event);
|
||||
});
|
||||
|
||||
if (isMyself) {
|
||||
Private.addControls.call(this);
|
||||
}
|
||||
|
||||
// suppress contextmenu
|
||||
this.video.oncontextmenu = function () { return false; };
|
||||
|
||||
if (this.$parent) this.setParent(this.$parent);
|
||||
};
|
||||
|
||||
VideoView.prototype.setParent = function($parent) {
|
||||
var self = this;
|
||||
this.$parent = $parent;
|
||||
this.$parent.off('.video' + this.id);
|
||||
this.$parent.on('mouseup.video' + this.id, function (event) {
|
||||
Handlers.mouseup.call(self, event);
|
||||
Private.cancelClick.call(self);
|
||||
});
|
||||
this.$parent.on('mousemove.video' + this.id, function (event) {
|
||||
Handlers.mousemove.call(self, event);
|
||||
});
|
||||
}
|
||||
|
||||
VideoView.prototype.setAvatar = function (src) {
|
||||
this.$avatar.attr('src', src);
|
||||
this.avatar = src;
|
||||
}
|
||||
|
||||
VideoView.prototype.remove = function () {
|
||||
this.$container.off();
|
||||
if (this.$parent) this.$parent.off('.video' + this.id);
|
||||
this.$container.remove();
|
||||
}
|
||||
|
||||
VideoView.prototype.videoOff = function () {
|
||||
this.$videoControl.addClass('active');
|
||||
this.$avatar.show();
|
||||
this.videoStatus = false;
|
||||
}
|
||||
|
||||
VideoView.prototype.videoOn = function () {
|
||||
this.$videoControl.removeClass('active');
|
||||
this.$avatar.hide();
|
||||
this.videoStatus = true;
|
||||
}
|
||||
|
||||
VideoView.prototype.audioOff = function () {
|
||||
this.$audioControl.addClass('active');
|
||||
this.audioStatus = false;
|
||||
}
|
||||
|
||||
VideoView.prototype.audioOn = function () {
|
||||
this.$audioControl.removeClass('active');
|
||||
this.audioStatus = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @static
|
||||
*/
|
||||
VideoView.events = {
|
||||
mousedown: "VideoView:mousedown",
|
||||
mouseup: "VideoView:mouseup",
|
||||
doubleClick: "VideoView:doubleClick",
|
||||
dragEnd: "VideoView:dragEnd",
|
||||
audioControlClick: "VideoView:audioControlClick",
|
||||
videoControlClick: "VideoView:videoControlClick",
|
||||
};
|
||||
|
||||
export default VideoView
|
7
frontend/src/Metamaps/Views/index.js
Normal file
7
frontend/src/Metamaps/Views/index.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import ExploreMaps from './ExploreMaps'
|
||||
import ChatView from './ChatView'
|
||||
import VideoView from './VideoView'
|
||||
import Room from './Room'
|
||||
|
||||
const Views = { ExploreMaps, ChatView, VideoView, Room }
|
||||
export default Views
|
|
@ -1,27 +1,32 @@
|
|||
/* global Metamaps, $ */
|
||||
|
||||
import _ from 'lodash'
|
||||
|
||||
import $jit from '../patched/JIT'
|
||||
|
||||
import Active from './Active'
|
||||
import JIT from './JIT'
|
||||
import Router from './Router'
|
||||
import TopicCard from './TopicCard'
|
||||
|
||||
/*
|
||||
* Metamaps.Visualize
|
||||
*
|
||||
* Dependencies:
|
||||
* - Metamaps.Active
|
||||
* - Metamaps.JIT
|
||||
* - Metamaps.Loading
|
||||
* - Metamaps.Metacodes
|
||||
* - Metamaps.Router
|
||||
* - Metamaps.Synapses
|
||||
* - Metamaps.TopicCard
|
||||
* - Metamaps.Topics
|
||||
* - Metamaps.Touch
|
||||
* - Metamaps.Visualize
|
||||
*/
|
||||
|
||||
Metamaps.Visualize = {
|
||||
const Visualize = {
|
||||
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 () {
|
||||
var self = Metamaps.Visualize
|
||||
var self = Visualize
|
||||
// disable awkward dragging of the canvas element that would sometimes happen
|
||||
$('#infovis-canvas').on('dragstart', function (event) {
|
||||
event.preventDefault()
|
||||
|
@ -35,19 +40,19 @@ Metamaps.Visualize = {
|
|||
|
||||
// prevent touch events on the canvas from default behaviour
|
||||
$('#infovis-canvas').bind('touchmove', function (event) {
|
||||
// Metamaps.JIT.touchPanZoomHandler(event)
|
||||
// JIT.touchPanZoomHandler(event)
|
||||
})
|
||||
|
||||
// prevent touch events on the canvas from default behaviour
|
||||
$('#infovis-canvas').bind('touchend touchcancel', function (event) {
|
||||
lastDist = 0
|
||||
if (!self.mGraph.events.touchMoved && !Metamaps.Touch.touchDragNode) Metamaps.TopicCard.hideCurrentCard()
|
||||
if (!self.mGraph.events.touchMoved && !Visualize.touchDragNode) TopicCard.hideCurrentCard()
|
||||
self.mGraph.events.touched = self.mGraph.events.touchMoved = false
|
||||
Metamaps.Touch.touchDragNode = false
|
||||
Visualize.touchDragNode = false
|
||||
})
|
||||
},
|
||||
computePositions: function () {
|
||||
var self = Metamaps.Visualize,
|
||||
var self = Visualize,
|
||||
mapping
|
||||
|
||||
if (self.type == 'RGraph') {
|
||||
|
@ -111,31 +116,31 @@ Metamaps.Visualize = {
|
|||
*
|
||||
*/
|
||||
render: function () {
|
||||
var self = Metamaps.Visualize, RGraphSettings, FDSettings
|
||||
var self = Visualize, RGraphSettings, FDSettings
|
||||
|
||||
if (self.type == 'RGraph' && (!self.mGraph || self.mGraph instanceof $jit.ForceDirected)) {
|
||||
// clear the previous canvas from #infovis
|
||||
$('#infovis').empty()
|
||||
|
||||
RGraphSettings = $.extend(true, {}, Metamaps.JIT.ForceDirected.graphSettings)
|
||||
RGraphSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
|
||||
|
||||
$jit.RGraph.Plot.NodeTypes.implement(Metamaps.JIT.ForceDirected.nodeSettings)
|
||||
$jit.RGraph.Plot.EdgeTypes.implement(Metamaps.JIT.ForceDirected.edgeSettings)
|
||||
$jit.RGraph.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
|
||||
$jit.RGraph.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
|
||||
|
||||
RGraphSettings.width = $(document).width()
|
||||
RGraphSettings.height = $(document).height()
|
||||
RGraphSettings.background = Metamaps.JIT.RGraph.background
|
||||
RGraphSettings.levelDistance = Metamaps.JIT.RGraph.levelDistance
|
||||
RGraphSettings.background = JIT.RGraph.background
|
||||
RGraphSettings.levelDistance = JIT.RGraph.levelDistance
|
||||
|
||||
self.mGraph = new $jit.RGraph(RGraphSettings)
|
||||
} else if (self.type == 'ForceDirected' && (!self.mGraph || self.mGraph instanceof $jit.RGraph)) {
|
||||
// clear the previous canvas from #infovis
|
||||
$('#infovis').empty()
|
||||
|
||||
FDSettings = $.extend(true, {}, Metamaps.JIT.ForceDirected.graphSettings)
|
||||
FDSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
|
||||
|
||||
$jit.ForceDirected.Plot.NodeTypes.implement(Metamaps.JIT.ForceDirected.nodeSettings)
|
||||
$jit.ForceDirected.Plot.EdgeTypes.implement(Metamaps.JIT.ForceDirected.edgeSettings)
|
||||
$jit.ForceDirected.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
|
||||
$jit.ForceDirected.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
|
||||
|
||||
FDSettings.width = $('body').width()
|
||||
FDSettings.height = $('body').height()
|
||||
|
@ -146,14 +151,14 @@ Metamaps.Visualize = {
|
|||
$('#infovis').empty()
|
||||
|
||||
// init ForceDirected3D
|
||||
self.mGraph = new $jit.ForceDirected3D(Metamaps.JIT.ForceDirected3D.graphSettings)
|
||||
self.mGraph = new $jit.ForceDirected3D(JIT.ForceDirected3D.graphSettings)
|
||||
self.cameraPosition = self.mGraph.canvas.canvases[0].camera.position
|
||||
} else {
|
||||
self.mGraph.graph.empty()
|
||||
}
|
||||
|
||||
|
||||
if (self.type == 'ForceDirected' && Metamaps.Active.Mapper) $.post('/maps/' + Metamaps.Active.Map.id + '/events/user_presence')
|
||||
if (self.type == 'ForceDirected' && Active.Mapper) $.post('/maps/' + Active.Map.id + '/events/user_presence')
|
||||
|
||||
function runAnimation () {
|
||||
Metamaps.Loading.hide()
|
||||
|
@ -161,22 +166,22 @@ Metamaps.Visualize = {
|
|||
if (!self.loadLater) {
|
||||
// load JSON data.
|
||||
var rootIndex = 0
|
||||
if (Metamaps.Active.Topic) {
|
||||
var node = _.find(Metamaps.JIT.vizData, function (node) {
|
||||
return node.id === Metamaps.Active.Topic.id
|
||||
if (Active.Topic) {
|
||||
var node = _.find(JIT.vizData, function (node) {
|
||||
return node.id === Active.Topic.id
|
||||
})
|
||||
rootIndex = _.indexOf(Metamaps.JIT.vizData, node)
|
||||
rootIndex = _.indexOf(JIT.vizData, node)
|
||||
}
|
||||
self.mGraph.loadJSON(Metamaps.JIT.vizData, rootIndex)
|
||||
self.mGraph.loadJSON(JIT.vizData, rootIndex)
|
||||
// compute positions and plot.
|
||||
self.computePositions()
|
||||
self.mGraph.busy = true
|
||||
if (self.type == 'RGraph') {
|
||||
self.mGraph.fx.animate(Metamaps.JIT.RGraph.animate)
|
||||
self.mGraph.fx.animate(JIT.RGraph.animate)
|
||||
} else if (self.type == 'ForceDirected') {
|
||||
self.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout)
|
||||
self.mGraph.animate(JIT.ForceDirected.animateSavedLayout)
|
||||
} else if (self.type == 'ForceDirected3D') {
|
||||
self.mGraph.animate(Metamaps.JIT.ForceDirected.animateFDLayout)
|
||||
self.mGraph.animate(JIT.ForceDirected.animateFDLayout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -203,17 +208,19 @@ Metamaps.Visualize = {
|
|||
hold()
|
||||
|
||||
// update the url now that the map is ready
|
||||
clearTimeout(Metamaps.Router.timeoutId)
|
||||
Metamaps.Router.timeoutId = setTimeout(function () {
|
||||
var m = Metamaps.Active.Map
|
||||
var t = Metamaps.Active.Topic
|
||||
clearTimeout(Router.timeoutId)
|
||||
Router.timeoutId = setTimeout(function () {
|
||||
var m = Active.Map
|
||||
var t = Active.Topic
|
||||
|
||||
if (m && window.location.pathname !== '/maps/' + m.id) {
|
||||
Metamaps.Router.navigate('/maps/' + m.id)
|
||||
Router.navigate('/maps/' + m.id)
|
||||
}
|
||||
else if (t && window.location.pathname !== '/topics/' + t.id) {
|
||||
Metamaps.Router.navigate('/topics/' + t.id)
|
||||
Router.navigate('/topics/' + t.id)
|
||||
}
|
||||
}, 800)
|
||||
}
|
||||
}; // end Metamaps.Visualize
|
||||
}
|
||||
|
||||
export default Visualize
|
107
frontend/src/Metamaps/index.js
Normal file
107
frontend/src/Metamaps/index.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* global $ */
|
||||
|
||||
import Account from './Account'
|
||||
import Active from './Active'
|
||||
import Admin from './Admin'
|
||||
import AutoLayout from './AutoLayout'
|
||||
import Backbone from './Backbone'
|
||||
import Control from './Control'
|
||||
import Create from './Create'
|
||||
import Debug from './Debug'
|
||||
import Filter from './Filter'
|
||||
import GlobalUI from './GlobalUI'
|
||||
import Import from './Import'
|
||||
import JIT from './JIT'
|
||||
import Listeners from './Listeners'
|
||||
import Map, { CheatSheet, InfoBox } from './Map'
|
||||
import Mapper from './Mapper'
|
||||
import Mobile from './Mobile'
|
||||
import Mouse from './Mouse'
|
||||
import Organize from './Organize'
|
||||
import PasteInput from './PasteInput'
|
||||
import Realtime from './Realtime'
|
||||
import Router from './Router'
|
||||
import Selected from './Selected'
|
||||
import Settings from './Settings'
|
||||
import Synapse from './Synapse'
|
||||
import SynapseCard from './SynapseCard'
|
||||
import Topic from './Topic'
|
||||
import TopicCard from './TopicCard'
|
||||
import Util from './Util'
|
||||
import Views from './Views'
|
||||
import Visualize from './Visualize'
|
||||
import ReactComponents from './ReactComponents'
|
||||
|
||||
Metamaps.Account = Account
|
||||
Metamaps.Active = Active
|
||||
Metamaps.Admin = Admin
|
||||
Metamaps.AutoLayout = AutoLayout
|
||||
Metamaps.Backbone = Backbone
|
||||
Metamaps.Control = Control
|
||||
Metamaps.Create = Create
|
||||
Metamaps.Debug = Debug
|
||||
Metamaps.Filter = Filter
|
||||
Metamaps.GlobalUI = GlobalUI
|
||||
Metamaps.Import = Import
|
||||
Metamaps.JIT = JIT
|
||||
Metamaps.Listeners = Listeners
|
||||
Metamaps.Map = Map
|
||||
Metamaps.Map.CheatSheet = CheatSheet
|
||||
Metamaps.Map.InfoBox = InfoBox
|
||||
Metamaps.Maps = {}
|
||||
Metamaps.Mapper = Mapper
|
||||
Metamaps.Mobile = Mobile
|
||||
Metamaps.Mouse = Mouse
|
||||
Metamaps.Organize = Organize
|
||||
Metamaps.PasteInput = PasteInput
|
||||
Metamaps.Realtime = Realtime
|
||||
Metamaps.ReactComponents = ReactComponents
|
||||
Metamaps.Router = Router
|
||||
Metamaps.Selected = Selected
|
||||
Metamaps.Settings = Settings
|
||||
Metamaps.Synapse = Synapse
|
||||
Metamaps.SynapseCard = SynapseCard
|
||||
Metamaps.Topic = Topic
|
||||
Metamaps.TopicCard = TopicCard
|
||||
Metamaps.Util = Util
|
||||
Metamaps.Views = Views
|
||||
Metamaps.Visualize = Visualize
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// initialize all the modules
|
||||
for (const prop in Metamaps) {
|
||||
// this runs the init function within each sub-object on the Metamaps one
|
||||
if (Metamaps.hasOwnProperty(prop) &&
|
||||
Metamaps[prop] != null &&
|
||||
Metamaps[prop].hasOwnProperty('init') &&
|
||||
typeof (Metamaps[prop].init) == 'function'
|
||||
) {
|
||||
Metamaps[prop].init()
|
||||
}
|
||||
}
|
||||
// load whichever page you are on
|
||||
if (Metamaps.currentSection === "explore") {
|
||||
const capitalize = Metamaps.currentPage.charAt(0).toUpperCase() + Metamaps.currentPage.slice(1)
|
||||
|
||||
Metamaps.Views.ExploreMaps.setCollection( Metamaps.Maps[capitalize] )
|
||||
if (Metamaps.currentPage === "mapper") {
|
||||
Views.ExploreMaps.fetchUserThenRender()
|
||||
}
|
||||
else {
|
||||
Views.ExploreMaps.render()
|
||||
}
|
||||
GlobalUI.showDiv('#explore')
|
||||
}
|
||||
else if (Metamaps.currentSection === "" && Active.Mapper) {
|
||||
Views.ExploreMaps.setCollection(Metamaps.Maps.Active)
|
||||
Views.ExploreMaps.render()
|
||||
GlobalUI.showDiv('#explore')
|
||||
}
|
||||
else if (Active.Map || Active.Topic) {
|
||||
Metamaps.Loading.show()
|
||||
JIT.prepareVizData()
|
||||
GlobalUI.showDiv('#infovis')
|
||||
}
|
||||
});
|
||||
|
||||
export default Metamaps
|
|
@ -1,18 +1,8 @@
|
|||
import React from 'react'
|
||||
// create global references to some utility libraries
|
||||
import ReactDOM from 'react-dom'
|
||||
import Backbone from 'backbone'
|
||||
import _ from 'underscore'
|
||||
import Maps from './components/Maps.js'
|
||||
|
||||
// this is optional really, if we import components directly React will be
|
||||
// in the bundle, so we won't need a global reference
|
||||
window.React = React
|
||||
window.ReactDOM = ReactDOM
|
||||
Backbone.$ = window.$
|
||||
window.Backbone = Backbone
|
||||
window._ = _
|
||||
|
||||
window.Metamaps = window.Metamaps || {}
|
||||
window.Metamaps.ReactComponents = {
|
||||
Maps
|
||||
}
|
||||
import Metamaps from './Metamaps'
|
||||
window.Metamaps = Metamaps
|
||||
|
|
|
@ -20,7 +20,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
(function () {
|
||||
|
||||
/*
|
||||
File: Core.js
|
||||
|
@ -34,7 +33,11 @@ THE SOFTWARE.
|
|||
This variable is the *only* global variable defined in the Toolkit.
|
||||
There are also other interesting properties attached to this variable described below.
|
||||
*/
|
||||
window.$jit = function(w) {
|
||||
// START METAMAPS CODE
|
||||
const $jit = function(w) {
|
||||
// ORIGINAL:
|
||||
// window.$jit = function(w) {
|
||||
// END METAMAPS CODE
|
||||
w = w || window;
|
||||
for(var k in $jit) {
|
||||
if($jit[k].$extend) {
|
||||
|
@ -3122,9 +3125,15 @@ var Canvas;
|
|||
};
|
||||
},
|
||||
translateToCenter: function(ps) {
|
||||
var size = this.getSize(),
|
||||
width = ps? (size.width - ps.width - this.translateOffsetX*2) : size.width;
|
||||
height = ps? (size.height - ps.height - this.translateOffsetY*2) : size.height;
|
||||
// START METAMAPS CODE
|
||||
var size = this.getSize();
|
||||
var width = ps ? (size.width - ps.width - this.translateOffsetX*2) : size.width;
|
||||
var height = ps ? (size.height - ps.height - this.translateOffsetY*2) : size.height;
|
||||
// ORIGINAL CODE
|
||||
// var size = this.getSize(),
|
||||
// width = ps? (size.width - ps.width - this.translateOffsetX*2) : size.width;
|
||||
// height = ps? (size.height - ps.height - this.translateOffsetY*2) : size.height;
|
||||
// END METAMAPS CODE
|
||||
var ctx = this.getCtx();
|
||||
ps && ctx.scale(1/this.scaleOffsetX, 1/this.scaleOffsetY);
|
||||
ctx.translate(width/2, height/2);
|
||||
|
@ -3232,7 +3241,7 @@ var Canvas;
|
|||
ctx = base.getCtx(),
|
||||
scale = base.scaleOffsetX;
|
||||
//var pattern = new Image();
|
||||
//pattern.src = "<%= asset_path('cubes.png') %>";
|
||||
//pattern.src = Metamaps.Erb['cubes.png']
|
||||
//var ptrn = ctx.createPattern(pattern, 'repeat');
|
||||
//ctx.fillStyle = ptrn;
|
||||
ctx.fillStyle = Metamaps.Settings.colors.background;
|
||||
|
@ -5634,7 +5643,11 @@ Graph.Op = {
|
|||
break;
|
||||
|
||||
case 'fade:seq': case 'fade': case 'fade:con':
|
||||
that = this;
|
||||
// START METAMAPS CODE
|
||||
var that = this;
|
||||
// ORIGINAL CODE:
|
||||
// that = this;
|
||||
// END METAMAPS CODE
|
||||
graph = viz.construct(json);
|
||||
|
||||
//set alpha to 0 for nodes to add.
|
||||
|
@ -5770,7 +5783,11 @@ Graph.Op = {
|
|||
break;
|
||||
|
||||
case 'fade:seq': case 'fade': case 'fade:con':
|
||||
that = this;
|
||||
// START METAMAPS CODE
|
||||
var that = this;
|
||||
// ORIGINAL CODE:
|
||||
// that = this;
|
||||
// END METAMAPS CODE
|
||||
graph = viz.construct(json);
|
||||
//preprocessing for nodes to delete.
|
||||
//get node property modes to interpolate
|
||||
|
@ -11312,7 +11329,4 @@ $jit.ForceDirected3D.$extend = true;
|
|||
|
||||
})($jit.ForceDirected3D);
|
||||
|
||||
|
||||
|
||||
|
||||
})();
|
||||
export default $jit
|
|
@ -1,13 +1,14 @@
|
|||
/* global describe, it */
|
||||
const chai = require('chai')
|
||||
const expect = chai.expect
|
||||
|
||||
Metamaps = {}
|
||||
require('../../app/assets/javascripts/src/Metamaps.Import')
|
||||
import chai from 'chai'
|
||||
|
||||
import Import from '../src/Metamaps/Import'
|
||||
|
||||
const { expect } = chai
|
||||
|
||||
describe('Metamaps.Import.js', function () {
|
||||
it('has a topic whitelist', function () {
|
||||
expect(Metamaps.Import.topicWhitelist).to.deep.equal(
|
||||
expect(Import.topicWhitelist).to.deep.equal(
|
||||
['id', 'name', 'metacode', 'x', 'y', 'description', 'link', 'permission']
|
||||
)
|
||||
})
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"scripts": {
|
||||
"build": "webpack",
|
||||
"build:watch": "webpack --watch",
|
||||
"test": "mocha frontend/test || (echo 'Run `npm install` to setup testing' && false)"
|
||||
"test": "mocha --compilers js:babel-core/register frontend/test || (echo 'Run `npm install` to setup testing' && false)"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -18,6 +18,7 @@
|
|||
},
|
||||
"homepage": "https://github.com/metamaps/metamaps#readme",
|
||||
"dependencies": {
|
||||
"autolinker": "^0.17.1",
|
||||
"babel-cli": "^6.11.4",
|
||||
"babel-loader": "^6.2.4",
|
||||
"babel-plugin-transform-class-properties": "^6.11.5",
|
||||
|
@ -27,9 +28,12 @@
|
|||
"chai": "^3.5.0",
|
||||
"jquery": "1.12.1",
|
||||
"mocha": "^3.0.2",
|
||||
"mocha-jsdom": "^1.1.0",
|
||||
"node-uuid": "1.2.0",
|
||||
"react": "^15.3.0",
|
||||
"react-dom": "^15.3.0",
|
||||
"requirejs": "^2.1.1",
|
||||
"socket.io": "0.9.12",
|
||||
"underscore": "^1.4.4",
|
||||
"webpack": "^1.13.1"
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "RoR-real-time",
|
||||
"description": "providing real-time sychronization for ruby on rails",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"socket.io": "0.9.12",
|
||||
"node-uuid": "1.2.0"
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue