Merge pull request #411 from metamaps/rails4

Upgrade to rails 4?
This commit is contained in:
Devin Howard 2015-10-23 21:09:49 +08:00
commit eb7ba35e14
50 changed files with 3036 additions and 1669 deletions

38
Gemfile
View file

@ -1,15 +1,12 @@
source 'https://rubygems.org'
ruby '2.1.3'
gem 'rails', '3.2.17'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'rails', '4.2.4'
gem 'devise'
gem 'redis'
gem 'pg'
gem 'cancan'
gem 'cancancan'
gem 'formula'
gem 'formtastic'
gem 'json'
@ -22,6 +19,10 @@ gem 'dotenv'
gem 'paperclip'
gem 'aws-sdk'
gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'jbuilder'
#gem 'therubyracer' #optional
#gem 'rb-readline'
@ -29,32 +30,21 @@ gem 'aws-sdk'
# in production environments by default.
group :assets do
gem 'sass-rails'
gem 'coffee-rails', '~> 3.2.1'
gem 'coffee-rails'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer'
gem 'uglifier', '>= 1.0.3'
gem 'uglifier'
end
group :production do #this is used on heroku
#gem 'rmagick'
gem 'rails_12factor'
end
gem 'jquery-rails', '2.1.2'
# To use ActiveModel has_secure_password
# gem 'bcrypt-ruby', '~> 3.0.0'
# To use Jbuilder templates for JSON
gem 'jbuilder', '0.8.2'
# Use unicorn as the web server
# gem 'unicorn'
# Deploy with Capistrano
# gem 'capistrano'
# To use debugger
# gem 'ruby-debug19', :require => 'ruby-debug'
group :development, :test do
gem 'pry-rails'
gem 'better_errors'
gem 'quiet_assets'
end

View file

@ -1,58 +1,71 @@
GEM
remote: https://rubygems.org/
specs:
actionmailer (3.2.17)
actionpack (= 3.2.17)
mail (~> 2.5.4)
actionpack (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
builder (~> 3.0.0)
actionmailer (4.2.4)
actionpack (= 4.2.4)
actionview (= 4.2.4)
activejob (= 4.2.4)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.4)
actionview (= 4.2.4)
activesupport (= 4.2.4)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.4)
activesupport (= 4.2.4)
builder (~> 3.1)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.5)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.17)
activesupport (= 3.2.17)
builder (~> 3.0.0)
activerecord (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
activesupport (3.2.17)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
arel (3.0.3)
aws-sdk (1.54.0)
aws-sdk-v1 (= 1.54.0)
aws-sdk-v1 (1.54.0)
json (~> 1.4)
nokogiri (>= 1.4.4)
bcrypt (3.1.7)
bcrypt (3.1.7-x86-mingw32)
best_in_place (2.1.0)
jquery-rails
rails (~> 3.1)
builder (3.0.4)
cancan (1.6.10)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (4.2.4)
activesupport (= 4.2.4)
globalid (>= 0.3.0)
activemodel (4.2.4)
activesupport (= 4.2.4)
builder (~> 3.1)
activerecord (4.2.4)
activemodel (= 4.2.4)
activesupport (= 4.2.4)
arel (~> 6.0)
activesupport (4.2.4)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
arel (6.0.3)
aws-sdk (2.1.19)
aws-sdk-resources (= 2.1.19)
aws-sdk-core (2.1.19)
jmespath (~> 1.0)
aws-sdk-resources (2.1.19)
aws-sdk-core (= 2.1.19)
bcrypt (3.1.10)
best_in_place (3.0.3)
actionpack (>= 3.2)
railties (>= 3.2)
better_errors (2.1.1)
coderay (>= 1.0.0)
erubis (>= 2.6.6)
rack (>= 0.9.0)
builder (3.2.2)
cancancan (1.12.0)
climate_control (0.0.3)
activesupport (>= 3.0)
cocaine (0.5.4)
cocaine (0.5.7)
climate_control (>= 0.0.3, < 1.0)
coffee-rails (3.2.2)
coderay (1.1.0)
coffee-rails (4.1.0)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
coffee-script (2.3.0)
railties (>= 4.0.0, < 5.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.8.0)
devise (3.4.0)
coffee-script-source (1.9.1.1)
devise (3.5.2)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
@ -61,92 +74,117 @@ GEM
warden (~> 1.2.3)
dotenv (2.0.0)
erubis (2.7.0)
execjs (2.2.1)
execjs (2.6.0)
ezcrypto (0.7.2)
formtastic (3.0.0)
formtastic (3.1.3)
actionpack (>= 3.2.13)
formula (1.0.1)
formula (1.1.1)
rails (> 3.0.0)
hike (1.2.3)
i18n (0.6.11)
jbuilder (0.8.2)
activesupport (>= 3.0.0)
journey (1.0.4)
jquery-rails (2.1.2)
railties (>= 3.1.0, < 5.0)
thor (~> 0.14)
json (1.8.1)
kaminari (0.16.1)
globalid (0.3.6)
activesupport (>= 4.1.0)
i18n (0.7.0)
jbuilder (2.3.1)
activesupport (>= 3.0.0, < 5)
multi_json (~> 1.2)
jmespath (1.0.2)
multi_json (~> 1.0)
jquery-rails (4.0.5)
rails-dom-testing (~> 1.0)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jquery-ui-rails (5.0.5)
railties (>= 3.2.16)
json (1.8.3)
kaminari (0.16.3)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.25.1)
mini_portile (0.6.0)
multi_json (1.10.1)
nokogiri (1.6.3.1)
mini_portile (= 0.6.0)
nokogiri (1.6.3.1-x86-mingw32)
mini_portile (= 0.6.0)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.6.3)
mime-types (>= 1.16, < 3)
method_source (0.8.2)
mime-types (2.6.1)
mimemagic (0.3.0)
mini_portile (0.6.2)
minitest (5.8.0)
multi_json (1.11.2)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
oauth (0.4.7)
orm_adapter (0.5.0)
paperclip (4.2.0)
activemodel (>= 3.0.0)
activesupport (>= 3.0.0)
cocaine (~> 0.5.3)
paperclip (4.3.0)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
cocaine (~> 0.5.5)
mime-types
pg (0.17.1)
pg (0.17.1-x86-mingw32)
polyglot (0.3.5)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
rack-ssl (1.3.4)
rack
rack-test (0.6.2)
mimemagic (= 0.3.0)
pg (0.18.3)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-rails (0.3.4)
pry (>= 0.9.10)
quiet_assets (1.1.0)
railties (>= 3.1, < 5.0)
rack (1.6.4)
rack-test (0.6.3)
rack (>= 1.0)
rails (3.2.17)
actionmailer (= 3.2.17)
actionpack (= 3.2.17)
activerecord (= 3.2.17)
activeresource (= 3.2.17)
activesupport (= 3.2.17)
bundler (~> 1.0)
railties (= 3.2.17)
rails3-jquery-autocomplete (1.0.14)
rails (>= 3.0)
railties (3.2.17)
actionpack (= 3.2.17)
activesupport (= 3.2.17)
rack-ssl (~> 1.3.2)
rails (4.2.4)
actionmailer (= 4.2.4)
actionpack (= 4.2.4)
actionview (= 4.2.4)
activejob (= 4.2.4)
activemodel (= 4.2.4)
activerecord (= 4.2.4)
activesupport (= 4.2.4)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.4)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
rails-dom-testing (1.0.7)
activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.2)
loofah (~> 2.0)
rails3-jquery-autocomplete (1.0.15)
rails (>= 3.2)
rails_12factor (0.0.3)
rails_serve_static_assets
rails_stdout_logging
rails_serve_static_assets (0.0.4)
rails_stdout_logging (0.0.4)
railties (4.2.4)
actionpack (= 4.2.4)
activesupport (= 4.2.4)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
rake (10.3.2)
rdoc (3.12.2)
json (~> 1.4)
redis (3.1.0)
responders (1.1.1)
railties (>= 3.2, < 4.2)
sass (3.4.5)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
sprockets (2.2.2)
hike (~> 1.2)
multi_json (~> 1.0)
thor (>= 0.18.1, < 2.0)
rake (10.4.2)
redis (3.2.1)
responders (2.1.0)
railties (>= 4.2.0, < 5)
sass (3.4.18)
sass-rails (5.0.4)
railties (>= 4.0.0, < 5.0)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
slop (3.6.0)
sprockets (3.3.4)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.3.3)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
thor (0.19.1)
thread_safe (0.3.4)
tilt (1.4.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.41)
uglifier (2.5.3)
thread_safe (0.3.5)
tilt (2.0.1)
tzinfo (1.2.2)
thread_safe (~> 0.1)
uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
uservoice-ruby (0.0.11)
@ -158,26 +196,30 @@ GEM
PLATFORMS
ruby
x86-mingw32
DEPENDENCIES
aws-sdk
best_in_place
cancan
coffee-rails (~> 3.2.1)
better_errors
cancancan
coffee-rails
devise
dotenv
formtastic
formula
jbuilder (= 0.8.2)
jquery-rails (= 2.1.2)
jbuilder
jquery-rails
jquery-ui-rails
json
kaminari
paperclip
pg
rails (= 3.2.17)
pry-rails
quiet_assets
rails (= 4.2.4)
rails3-jquery-autocomplete
rails_12factor
redis
sass-rails
uglifier (>= 1.0.3)
uglifier
uservoice-ruby

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -616,7 +616,7 @@ Metamaps.GlobalUI.Search = {
var self = Metamaps.GlobalUI.Search;
function toggleResultSet(set) {
var s = $('.tt-dataset-' + set + ' .tt-suggestions');
var s = $('.tt-dataset-' + set + ' .tt-dataset');
if (s.css('height') == '0px') {
s.css({
'height': 'auto',

View file

@ -37,7 +37,7 @@ Metamaps.Settings = {
background: '#18202E',
text: '#DDD'
}
}
},
};
Metamaps.Touch = {
@ -157,7 +157,7 @@ Metamaps.Backbone.init = function () {
this.on('saved', this.savedEvent);
this.on('nowPrivate', function(){
var removeTopicData = {
topicid: this.id
mappableid: this.id
};
$(document).trigger(Metamaps.JIT.events.removeTopic, [removeTopicData]);
@ -165,7 +165,7 @@ Metamaps.Backbone.init = function () {
this.on('noLongerPrivate', function(){
var newTopicData = {
mappingid: this.getMapping().id,
topicid: this.id
mappableid: this.id
};
$(document).trigger(Metamaps.JIT.events.newTopic, [newTopicData]);
@ -194,7 +194,8 @@ Metamaps.Backbone.init = function () {
return Metamaps.Mappings.findWhere({
map_id: Metamaps.Active.Map.id,
topic_id: this.isNew() ? this.cid : this.id
mappable_type: "Topic",
mappable_id: this.isNew() ? this.cid : this.id
});
},
createNode: function () {
@ -320,14 +321,14 @@ Metamaps.Backbone.init = function () {
this.on('noLongerPrivate', function(){
var newSynapseData = {
mappingid: this.getMapping().id,
synapseid: this.id
mappableid: this.id
};
$(document).trigger(Metamaps.JIT.events.newSynapse, [newSynapseData]);
});
this.on('nowPrivate', function(){
$(document).trigger(Metamaps.JIT.events.removeSynapse, [{
synapseid: this.id
mappableid: this.id
}]);
});
@ -370,7 +371,8 @@ Metamaps.Backbone.init = function () {
return Metamaps.Mappings.findWhere({
map_id: Metamaps.Active.Map.id,
synapse_id: this.isNew() ? this.cid : this.id
mappable_type: "Synapse",
mappable_id: this.isNew() ? this.cid : this.id
});
},
createEdge: function () {
@ -457,11 +459,11 @@ Metamaps.Backbone.init = function () {
return Metamaps.Map.get(this.get('map_id'));
},
getTopic: function () {
if (this.get('category') === 'Topic') return Metamaps.Topic.get(this.get('topic_id'));
if (this.get('mappable_type') === 'Topic') return Metamaps.Topic.get(this.get('mappable_id'));
else return false;
},
getSynapse: function () {
if (this.get('category') === 'Synapse') return Metamaps.Synapse.get(this.get('synapse_id'));
if (this.get('mappable_type') === 'Synapse') return Metamaps.Synapse.get(this.get('mappable_id'));
else return false;
}
});
@ -664,6 +666,15 @@ Metamaps.Create = {
Metamaps.Create.newTopic.name = $(this).val();
});
var topicBloodhound = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/topics/autocomplete_topic?term=%QUERY',
wildcard: '%QUERY',
},
});
// initialize the autocomplete results for the metacode spinner
$('#topic_name').typeahead(
{
@ -672,16 +683,18 @@ Metamaps.Create = {
[{
name: 'topic_autocomplete',
limit: 8,
template: $('#topicAutocompleteTemplate').html(),
remote: {
url: '/topics/autocomplete_topic?term=%QUERY'
display: function (s) { return s.label; },
templates: {
suggestion: function(s) {
return Hogan.compile($('#topicAutocompleteTemplate').html()).render(s);
},
engine: Hogan
},
source: topicBloodhound,
}]
);
// tell the autocomplete to submit the form with the topic you clicked on if you pick from the autocomplete
$('#topic_name').bind('typeahead:selected', function (event, datum, dataset) {
$('#topic_name').bind('typeahead:select', function (event, datum, dataset) {
Metamaps.Topic.getTopicFromAutocomplete(datum.id);
});
@ -714,7 +727,7 @@ Metamaps.Create = {
},
hide: function () {
$('#new_topic').fadeOut('fast');
$("#topic_name").typeahead('setQuery', '');
$("#topic_name").typeahead('val', '');
Metamaps.Create.newTopic.beingCreated = false;
}
},
@ -726,6 +739,31 @@ Metamaps.Create = {
Metamaps.Create.newSynapse.description = $(this).val();
});
var synapseBloodhound = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/search/synapses?term=%QUERY',
wildcard: '%QUERY',
},
});
var existingSynapseBloodhound = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/search/synapses?topic1id=%TOPIC1&topic2id=%TOPIC2',
prepare: function(query, settings) {
var self = Metamaps.Create.newSynapse;
if (Metamaps.Selected.Nodes.length < 2) {
settings.url = settings.url.replace("%TOPIC1", self.topic1id).replace("%TOPIC2", self.topic2id);
return settings;
} else {
return null;
}
},
},
});
// initialize the autocomplete results for synapse creation
$('#synapse_desc').typeahead(
{
@ -733,28 +771,29 @@ Metamaps.Create = {
},
[{
name: 'synapse_autocomplete',
template: "<div class='genericSynapseDesc'>{{label}}</div>",
remote: {
url: '/search/synapses?term=%QUERY'
display: function(s) { return s.label; },
templates: {
suggestion: function(s) {
return Hogan.compile("<div class='genericSynapseDesc'>{{label}}</div>").render(s);
},
engine: Hogan
},
source: synapseBloodhound,
},
{
name: 'existing_synapses',
limit: 50,
template: $('#synapseAutocompleteTemplate').html(),
remote: {
url: '/search/synapses',
replace: function () {
return self.getSearchQuery();
}
display: function(s) { return s.label; },
templates: {
suggestion: function(s) {
return Hogan.compile($('#synapseAutocompleteTemplate').html()).render(s);
},
engine: Hogan,
header: "<h3>Existing synapses</h3>"
},
source: existingSynapseBloodhound,
}]
);
$('#synapse_desc').bind('typeahead:selected', function (event, datum, dataset) {
$('#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);
}
@ -777,7 +816,7 @@ Metamaps.Create = {
},
hide: function () {
$('#new_synapse').fadeOut('fast');
$("#synapse_desc").typeahead('setQuery', '');
$("#synapse_desc").typeahead('val', '');
Metamaps.Create.newSynapse.beingCreated = false;
Metamaps.Create.newTopic.addSynapse = false;
Metamaps.Create.newSynapse.topic1id = 0;
@ -785,13 +824,6 @@ Metamaps.Create = {
Metamaps.Mouse.synapseStartCoordinates = [];
Metamaps.Visualize.mGraph.plot();
},
getSearchQuery: function () {
var self = Metamaps.Create.newSynapse;
if (Metamaps.Selected.Nodes.length < 2) {
return '/search/synapses?topic1id=' + self.topic1id + '&topic2id=' + self.topic2id;
} else return '';
}
}
}; // end Metamaps.Create
@ -1534,8 +1566,6 @@ Metamaps.SynapseCard = {
////////////////////// END TOPIC AND SYNAPSE CARDS //////////////////////////////////
/*
*
* VISUALIZE
@ -2511,7 +2541,7 @@ Metamaps.Realtime = {
if (!self.status) return;
function test() {
function waitThenRenderTopic() {
if (topic && mapping && mapper) {
Metamaps.Topic.renderTopic(mapping, topic, false, false);
}
@ -2529,7 +2559,7 @@ Metamaps.Realtime = {
Metamaps.Mapper.get(data.mapperid, mapperCallback);
}
$.ajax({
url: "/topics/" + data.topicid + ".json",
url: "/topics/" + data.mappableid + ".json",
success: function (response) {
Metamaps.Topics.add(response);
topic = Metamaps.Topics.get(response.id);
@ -2549,7 +2579,7 @@ Metamaps.Realtime = {
}
});
test();
waitThenRenderTopic();
},
// removeTopic
sendDeleteTopic: function (data) {
@ -2576,7 +2606,7 @@ Metamaps.Realtime = {
if (!self.status) return;
var topic = Metamaps.Topics.get(data.topicid);
var topic = Metamaps.Topics.get(data.mappableid);
if (topic) {
var node = topic.get('node');
var mapping = topic.getMapping();
@ -2604,7 +2634,7 @@ Metamaps.Realtime = {
if (!self.status) return;
function test() {
function waitThenRenderSynapse() {
if (synapse && mapping && mapper) {
topic1 = synapse.getTopic1();
node1 = topic1.get('node');
@ -2627,7 +2657,7 @@ Metamaps.Realtime = {
Metamaps.Mapper.get(data.mapperid, mapperCallback);
}
$.ajax({
url: "/synapses/" + data.synapseid + ".json",
url: "/synapses/" + data.mappableid + ".json",
success: function (response) {
Metamaps.Synapses.add(response);
synapse = Metamaps.Synapses.get(response.id);
@ -2646,7 +2676,7 @@ Metamaps.Realtime = {
cancel = true;
}
});
test();
waitThenRenderSynapse();
},
// deleteSynapse
sendDeleteSynapse: function (data) {
@ -2674,7 +2704,7 @@ Metamaps.Realtime = {
if (!self.status) return;
var synapse = Metamaps.Synapses.get(data.synapseid);
var synapse = Metamaps.Synapses.get(data.mappableid);
if (synapse) {
var edge = synapse.get('edge');
var mapping = synapse.getMapping();
@ -2784,12 +2814,12 @@ Metamaps.Control = {
var permToDelete = Metamaps.Active.Mapper.id === topic.get('user_id') || Metamaps.Active.Mapper.get('admin');
if (permToDelete) {
var topicid = topic.id;
var mappableid = topic.id;
var mapping = node.getData('mapping');
topic.destroy();
Metamaps.Mappings.remove(mapping);
$(document).trigger(Metamaps.JIT.events.deleteTopic, [{
topicid: topicid
mappableid: mappableid
}]);
Metamaps.Control.hideNode(nodeid);
} else {
@ -2828,12 +2858,12 @@ Metamaps.Control = {
}
var topic = node.getData('topic');
var topicid = topic.id;
var mappableid = topic.id;
var mapping = node.getData('mapping');
mapping.destroy();
Metamaps.Topics.remove(topic);
$(document).trigger(Metamaps.JIT.events.removeTopic, [{
topicid: topicid
mappableid: mappableid
}]);
Metamaps.Control.hideNode(nodeid);
},
@ -2957,7 +2987,7 @@ Metamaps.Control = {
Metamaps.Control.hideEdge(edge);
}
var synapseid = synapse.id;
var mappableid = synapse.id;
synapse.destroy();
// the server will destroy the mapping, we just need to remove it here
@ -2968,7 +2998,7 @@ Metamaps.Control = {
delete edge.data.$displayIndex;
}
$(document).trigger(Metamaps.JIT.events.deleteSynapse, [{
synapseid: synapseid
mappableid: mappableid
}]);
} else {
Metamaps.GlobalUI.notifyUser('Only synapses you created can be deleted');
@ -3013,7 +3043,7 @@ Metamaps.Control = {
var synapse = edge.getData("synapses")[index];
var mapping = edge.getData("mappings")[index];
var synapseid = synapse.id;
var mappableid = synapse.id;
mapping.destroy();
Metamaps.Synapses.remove(synapse);
@ -3024,7 +3054,7 @@ Metamaps.Control = {
delete edge.data.$displayIndex;
}
$(document).trigger(Metamaps.JIT.events.removeSynapse, [{
synapseid: synapseid
mappableid: mappableid
}]);
},
hideSelectedEdges: function () {
@ -4024,14 +4054,14 @@ Metamaps.Topic = {
var mappingSuccessCallback = function (mappingModel, response) {
var newTopicData = {
mappingid: mappingModel.id,
topicid: mappingModel.get('topic_id')
mappableid: mappingModel.get('mappable_id')
};
$(document).trigger(Metamaps.JIT.events.newTopic, [newTopicData]);
};
var topicSuccessCallback = function (topicModel, response) {
if (Metamaps.Active.Map) {
mapping.save({ topic_id: topicModel.id }, {
mapping.save({ mappable_id: topicModel.id }, {
success: mappingSuccessCallback,
error: function (model, response) {
console.log('error saving mapping to database');
@ -4081,10 +4111,10 @@ Metamaps.Topic = {
Metamaps.Topics.add(topic);
var mapping = new Metamaps.Backbone.Mapping({
category: "Topic",
xloc: Metamaps.Create.newTopic.x,
yloc: Metamaps.Create.newTopic.y,
topic_id: topic.cid
mappable_id: topic.cid,
mappable_type: "Topic",
});
Metamaps.Mappings.add(mapping);
@ -4103,10 +4133,10 @@ Metamaps.Topic = {
var topic = self.get(id);
var mapping = new Metamaps.Backbone.Mapping({
category: "Topic",
xloc: Metamaps.Create.newTopic.x,
yloc: Metamaps.Create.newTopic.y,
topic_id: topic.id
mappable_type: "Topic",
mappable_id: topic.id,
});
Metamaps.Mappings.add(mapping);
@ -4121,10 +4151,10 @@ Metamaps.Topic = {
var nextCoords = Metamaps.Map.getNextCoord();
var mapping = new Metamaps.Backbone.Mapping({
category: "Topic",
xloc: nextCoords.x,
yloc: nextCoords.y,
topic_id: topic.id
mappable_type: "Topic",
mappable_id: topic.id,
});
Metamaps.Mappings.add(mapping);
@ -4195,14 +4225,14 @@ Metamaps.Synapse = {
var mappingSuccessCallback = function (mappingModel, response) {
var newSynapseData = {
mappingid: mappingModel.id,
synapseid: mappingModel.get('synapse_id')
mappableid: mappingModel.get('mappable_id')
};
$(document).trigger(Metamaps.JIT.events.newSynapse, [newSynapseData]);
};
var synapseSuccessCallback = function (synapseModel, response) {
if (Metamaps.Active.Map) {
mapping.save({ synapse_id: synapseModel.id }, {
mapping.save({ mappable_id: synapseModel.id }, {
success: mappingSuccessCallback
});
}
@ -4259,8 +4289,8 @@ Metamaps.Synapse = {
Metamaps.Synapses.add(synapse);
mapping = new Metamaps.Backbone.Mapping({
category: "Synapse",
synapse_id: synapse.cid
mappable_type: "Synapse",
mappable_id: synapse.cid,
});
Metamaps.Mappings.add(mapping);
@ -4280,8 +4310,8 @@ Metamaps.Synapse = {
var synapse = self.get(id);
var mapping = new Metamaps.Backbone.Mapping({
category: "Synapse",
synapse_id: synapse.id
mappable_type: "Synapse",
mappable_id: synapse.id,
});
Metamaps.Mappings.add(mapping);

View file

@ -1373,13 +1373,14 @@ h3.realtimeBoxTitle {
/* topic and synapse autocomplete */
#new_topic .tt-suggestion.tt-is-under-cursor,
#new_topic .tt-suggestion.tt-is-under-mouse-cursor,
#new_synapse .tt-suggestion.tt-is-under-cursor,
#new_synapse .tt-suggestion.tt-is-under-mouse-cursor {
#new_topic .tt-suggestion:hover,
#new_topic .tt-suggestion.tt-cursor,
#new_synapse .tt-suggestion:hover,
#new_synapse .tt-suggestion.tt-cursor {
background: #E0E0E0;
}
#new_topic .tt-suggestion,
#new_synapse .tt-dataset h3,
#new_synapse .tt-suggestion {
background: #F5F5F5;
position: relative;
@ -1421,12 +1422,12 @@ h3.realtimeBoxTitle {
background-image: url(arrowright_sprite.png);
background-position: 0 -32px;
}
#new_topic .tt-suggestion.tt-is-under-cursor .expandTopicMetadata,
#new_topic .tt-suggestion.tt-is-under-mouse-cursor .expandTopicMetadata {
#new_topic .tt-suggestion:hover .expandTopicMetadata,
#new_topic .tt-suggestion.tt-cursor .expandTopicMetadata {
display: block;
}
#new_topic .tt-suggestion.tt-is-under-cursor .topicMetadata,
#new_topic .tt-suggestion.tt-is-under-mouse-cursor .topicMetadata {
#new_topic .tt-suggestion:hover .topicMetadata,
#new_topic .tt-suggestion.tt-cursor .topicMetadata {
display: block;
}
#new_topic .topicMetadata {

View file

@ -301,7 +301,7 @@
.sidebarSearch .tt-dropdown-menu .maximizeResults {
background-position: -32px 0;
}
.sidebarSearch .tt-suggestions {
.sidebarSearch .tt-dataset {
overflow: visible;
}
.sidebarSearch .tt-suggestion {
@ -310,7 +310,7 @@
padding: 8px 0;
}
.sidebarSearch .tt-is-under-cursor,
.sidebarSearch .tt-is-under-mouse-cursor {
.sidebarSearch .tt-suggestion:hover {
background: #E0E0E0;
}

View file

@ -37,7 +37,7 @@ private
end
def require_admin
unless authenticated? && user.admin
unless authenticated? && admin?
redirect_to root_url, notice: "You need to be an admin for that."
return false
end

View file

@ -68,25 +68,20 @@ class MainController < ApplicationController
else
search = term.downcase + '%'
if !user
@topics = Topic.where('LOWER("name") like ?', search).where('metacode_id = ?', filterByMetacode.id).order('"name"')
@topics2 = Topic.where('LOWER("name") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"')
@topics3 = Topic.where('LOWER("desc") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"')
@topics4 = Topic.where('LOWER("link") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"')
@topics = @topics + (@topics2 - @topics)
@topics = @topics + (@topics3 - @topics)
@topics = @topics + (@topics4 - @topics)
elsif user
@topics = Topic.where('LOWER("name") like ?', search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"')
@topics2 = Topic.where('LOWER("name") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"')
@topics3 = Topic.where('LOWER("desc") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"')
@topics4 = Topic.where('LOWER("link") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"')
@topics = @topics + (@topics2 - @topics)
@topics = @topics + (@topics3 - @topics)
@topics = @topics + (@topics4 - @topics)
if user
@topics = Set.new(Topic.where('LOWER("name") like ?', search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
@topics2 = Set.new(Topic.where('LOWER("name") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
@topics3 = Set.new(Topic.where('LOWER("desc") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
@topics4 = Set.new(Topic.where('LOWER("link") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
else
@topics = Set.new(Topic.where('LOWER("name") like ?', search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
@topics2 = Set.new(Topic.where('LOWER("name") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
@topics3 = Set.new(Topic.where('LOWER("desc") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
@topics4 = Set.new(Topic.where('LOWER("link") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
end
#get unique elements only through the magic of Sets
@topics = (@topics + @topics2 + @topics3 + @topics4).to_a
end
elsif desc
search = '%' + term.downcase + '%'
@ -127,7 +122,7 @@ class MainController < ApplicationController
end
#read this next line as 'delete a topic if its private and you're either 1. logged out or 2. logged in but not the topic creator
@topics.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
render json: autocomplete_array_json(@topics)
end
@ -163,7 +158,7 @@ class MainController < ApplicationController
end
#read this next line as 'delete a map if its private and you're either 1. logged out or 2. logged in but not the map creator
@maps.delete_if {|m| m.permission == "private" && (!authenticated? || (authenticated? && @current.id != m.user_id)) }
@maps.to_a.delete_if {|m| m.permission == "private" && (!authenticated? || (authenticated? && @current.id != m.user_id)) }
render json: autocomplete_map_array_json(@maps)
end
@ -194,12 +189,12 @@ class MainController < ApplicationController
topic2id = params[:topic2id]
if term && !term.empty?
@synapses = Synapse.select('DISTINCT "desc"').where('LOWER("desc") like ?', '%' + term.downcase + '%').order('"desc"')
@synapses = Synapse.where('LOWER("desc") like ?', '%' + term.downcase + '%').order('"desc"')
# remove any duplicate synapse types that just differ by
# leading or trailing whitespaces
collectedDesc = []
@synapses.delete_if {|s|
@synapses.to_a.uniq(&:desc).delete_if {|s|
desc = s.desc == nil || s.desc == "" ? "" : s.desc.strip
if collectedDesc.index(desc) == nil
collectedDesc.push(desc)
@ -211,23 +206,20 @@ class MainController < ApplicationController
#limit to 5 results
@synapses = @synapses.slice(0,5)
render json: autocomplete_synapse_generic_json(@synapses)
elsif topic1id && !topic1id.empty?
@one = Synapse.where('node1_id = ? AND node2_id = ?', topic1id, topic2id)
@two = Synapse.where('node2_id = ? AND node1_id = ?', topic1id, topic2id)
@synapses = @one + @two
@synapses.sort! {|s1,s2| s1.desc <=> s2.desc }
@synapses.sort! {|s1,s2| s1.desc <=> s2.desc }.to_a
#read this next line as 'delete a synapse if its private and you're either 1. logged out or 2. logged in but not the synapse creator
@synapses.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
render json: autocomplete_synapse_array_json(@synapses)
#permissions
@synapses.delete_if {|s| s.permission == "private" && !authenticated? }
@synapses.delete_if {|s| s.permission == "private" && authenticated? && @current.id != s.user_id }
else
@synapses = []
render json: autocomplete_synapse_array_json(@synapses)
end
render json: autocomplete_synapse_array_json(@synapses)
end
end

View file

@ -13,7 +13,7 @@ class MappingsController < ApplicationController
# POST /mappings.json
def create
@mapping = Mapping.new(params[:mapping])
@mapping = Mapping.new(mapping_params)
@mapping.map.touch(:updated_at)
@ -30,7 +30,7 @@ class MappingsController < ApplicationController
@mapping.map.touch(:updated_at)
if @mapping.update_attributes(params[:mapping])
if @mapping.update_attributes(mapping_params)
head :no_content
else
render json: @mapping.errors, status: :unprocessable_entity
@ -48,4 +48,10 @@ class MappingsController < ApplicationController
head :no_content
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def mapping_params
params.require(:mapping).permit(:id, :xloc, :yloc, :mappable_id, :mappable_type, :map_id, :user_id)
end
end

View file

@ -72,14 +72,10 @@ class MapsController < ApplicationController
respond_to do |format|
format.html {
@allmappers = @map.contributors
@alltopics = @map.topics.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@allsynapses = @map.synapses.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
@allmappings = @map.mappings.delete_if {|m|
if m.category == "Synapse"
object = m.synapse
elsif m.category == "Topic"
object = m.topic
end
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
@allmappings = @map.mappings.to_a.delete_if {|m|
object = m.mappable
!object || (object.permission == "private" && (!authenticated? || (authenticated? && @current.id != object.user_id)))
}
@ -100,14 +96,10 @@ class MapsController < ApplicationController
end
@allmappers = @map.contributors
@alltopics = @map.topics.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@allsynapses = @map.synapses.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
@allmappings = @map.mappings.delete_if {|m|
if m.category == "Synapse"
object = m.synapse
elsif m.category == "Topic"
object = m.topic
end
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
@allmappings = @map.mappings.to_a.delete_if {|m|
object = m.mappable
!object || (object.permission == "private" && (!authenticated? || (authenticated? && @current.id != object.user_id)))
}
@ -141,7 +133,6 @@ class MapsController < ApplicationController
@all.each do |topic|
topic = topic.split('/')
@mapping = Mapping.new()
@mapping.category = "Topic"
@mapping.user = @user
@mapping.map = @map
@mapping.topic = Topic.find(topic[0])
@ -155,7 +146,6 @@ class MapsController < ApplicationController
@synAll = @synAll.split(',')
@synAll.each do |synapse_id|
@mapping = Mapping.new()
@mapping.category = "Synapse"
@mapping.user = @user
@mapping.map = @map
@mapping.synapse = Synapse.find(synapse_id)
@ -180,7 +170,7 @@ class MapsController < ApplicationController
respond_to do |format|
if !@map
format.json { render json: "unauthorized" }
elsif @map.update_attributes(params[:map])
elsif @map.update_attributes(map_params)
format.json { head :no_content }
else
format.json { render json: @map.errors, status: :unprocessable_entity }
@ -218,15 +208,7 @@ class MapsController < ApplicationController
@map = Map.find(params[:id]).authorize_to_delete(@current)
if @map
@mappings = @map.mappings
@mappings.each do |mapping|
mapping.delete
end
@map.delete
end
@map.delete if @map
respond_to do |format|
format.json {
@ -238,4 +220,11 @@ class MapsController < ApplicationController
}
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def map_params
params.require(:map).permit(:id, :name, :arranged, :desc, :permission, :user_id)
end
end

View file

@ -45,7 +45,7 @@ class MetacodeSetsController < ApplicationController
# POST /metacode_sets.json
def create
@user = current_user
@metacode_set = MetacodeSet.new(params[:metacode_set])
@metacode_set = MetacodeSet.new(metacode_set_params)
@metacode_set.user_id = @user.id
respond_to do |format|
@ -70,7 +70,7 @@ class MetacodeSetsController < ApplicationController
@metacode_set = MetacodeSet.find(params[:id])
respond_to do |format|
if @metacode_set.update_attributes(params[:metacode_set])
if @metacode_set.update_attributes(metacode_set_params)
# build an array of the IDs of the metacodes currently in the set
@currentMetacodes = @metacode_set.metacodes.map{ |m| m.id.to_s }
@ -116,4 +116,11 @@ class MetacodeSetsController < ApplicationController
format.json { head :no_content }
end
end
private
def metacode_set_params
params.require(:metacode_set).permit(:desc, :mapperContributed, :name)
end
end

View file

@ -51,7 +51,7 @@ class MetacodesController < ApplicationController
# POST /metacodes
# POST /metacodes.json
def create
@metacode = Metacode.new(params[:metacode])
@metacode = Metacode.new(metacode_params)
respond_to do |format|
if @metacode.save
@ -70,7 +70,7 @@ class MetacodesController < ApplicationController
@metacode = Metacode.find(params[:id])
respond_to do |format|
if @metacode.update_attributes(params[:metacode])
if @metacode.update_attributes(metacode_params)
format.html { redirect_to metacodes_url, notice: 'Metacode was successfully updated.' }
format.json { head :no_content }
else
@ -93,4 +93,11 @@ class MetacodesController < ApplicationController
# format.json { head :no_content }
# end
# end
private
# Never trust parameters from the scary internet, only allow the white list through.
def metacode_params
params.require(:metacode).permit(:id, :name, :icon, :color)
end
end

View file

@ -21,7 +21,7 @@ class SynapsesController < ApplicationController
# POST /synapses
# POST /synapses.json
def create
@synapse = Synapse.new(params[:synapse])
@synapse = Synapse.new(synapse_params)
respond_to do |format|
if @synapse.save
@ -38,7 +38,7 @@ class SynapsesController < ApplicationController
@synapse = Synapse.find(params[:id])
respond_to do |format|
if @synapse.update_attributes(params[:synapse])
if @synapse.update_attributes(synapse_params)
format.json { head :no_content }
else
format.json { render json: @synapse.errors, status: :unprocessable_entity }
@ -50,18 +50,16 @@ class SynapsesController < ApplicationController
def destroy
@current = current_user
@synapse = Synapse.find(params[:id]).authorize_to_delete(@current)
if @synapse
@synapse.mappings.each do |m|
m.map.touch(:updated_at)
m.delete
end
@synapse.delete
end
@synapse.delete if @synapse
respond_to do |format|
format.json { head :no_content }
end
end
private
def synapse_params
params.require(:synapse).permit(:id, :desc, :category, :weight, :permission, :node1_id, :node2_id, :user_id)
end
end

View file

@ -10,12 +10,11 @@ class TopicsController < ApplicationController
@current = current_user
term = params[:term]
if term && !term.empty?
# !connor term here needs to have .downcase
@topics = Topic.where('LOWER("name") like ?', term.downcase + '%').order('"name"')
#read this next line as 'delete a topic if its private and you're either
#1. logged out or 2. logged in but not the topic creator
@topics.delete_if {|t| t.permission == "private" &&
@topics.to_a.delete_if {|t| t.permission == "private" &&
(!authenticated? || (authenticated? && @current.id != t.user_id)) }
else
@topics = []
@ -35,7 +34,7 @@ class TopicsController < ApplicationController
respond_to do |format|
format.html {
@alltopics = ([@topic] + @topic.relatives).delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) } # should limit to topics visible to user
@allsynapses = @topic.synapses.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
@allsynapses = @topic.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
@allcreators = []
@alltopics.each do |t|
@ -64,8 +63,8 @@ class TopicsController < ApplicationController
redirect_to root_url, notice: "Access denied. That topic is private." and return
end
@alltopics = @topic.relatives.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@allsynapses = @topic.synapses.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
@alltopics = @topic.relatives.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@allsynapses = @topic.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
@allcreators = []
@allcreators.push(@topic.user)
@alltopics.each do |t|
@ -101,7 +100,7 @@ class TopicsController < ApplicationController
@topicsAlreadyHas = params[:network] ? params[:network].split(',') : []
@alltopics = @topic.relatives.delete_if {|t|
@alltopics = @topic.relatives.to_a.delete_if {|t|
@topicsAlreadyHas.index(t.id.to_s) != nil ||
(t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)))
}
@ -133,7 +132,7 @@ class TopicsController < ApplicationController
@topicsAlreadyHas = params[:network] ? params[:network].split(',') : []
@alltopics = @topic.relatives.delete_if {|t|
@alltopics = @topic.relatives.to_a.delete_if {|t|
@topicsAlreadyHas.index(t.id.to_s) != nil ||
(params[:metacode] && t.metacode_id.to_s != params[:metacode]) ||
(t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)))
@ -141,7 +140,7 @@ class TopicsController < ApplicationController
@alltopics.uniq!
@allsynapses = @topic.synapses.delete_if {|s|
@allsynapses = @topic.synapses.to_a.delete_if {|s|
(s.topic1 == @topic && @alltopics.index(s.topic2) == nil) ||
(s.topic2 == @topic && @alltopics.index(s.topic1) == nil)
}
@ -172,7 +171,7 @@ class TopicsController < ApplicationController
# POST /topics
# POST /topics.json
def create
@topic = Topic.new(params[:topic])
@topic = Topic.new(topic_params)
respond_to do |format|
if @topic.save
@ -189,7 +188,7 @@ class TopicsController < ApplicationController
@topic = Topic.find(params[:id])
respond_to do |format|
if @topic.update_attributes(params[:topic])
if @topic.update_attributes(topic_params)
format.json { head :no_content }
else
format.json { render json: @topic.errors, status: :unprocessable_entity }
@ -201,36 +200,16 @@ class TopicsController < ApplicationController
def destroy
@current = current_user
@topic = Topic.find(params[:id]).authorize_to_delete(@current)
if @topic
@synapses = @topic.synapses
@mappings = @topic.mappings
@synapses.each do |synapse|
synapse.mappings.each do |m|
@map = m.map
@map.touch(:updated_at)
m.delete
end
synapse.delete
end
@mappings.each do |mapping|
@map = mapping.map
@map.touch(:updated_at)
mapping.delete
end
@topic.delete
end
@topic.delete if @topic
respond_to do |format|
format.json { head :no_content }
end
end
private
def topic_params
params.require(:topic).permit(:id, :name, :desc, :link, :permission, :user_id, :metacode_id)
end
end

View file

@ -98,4 +98,11 @@ class UsersController < ApplicationController
end
end
private
def user_params
params.require(:user).permit(:name, :email, :image, :password,
:password_confirmation, :code, :joinedwithcode, :remember_me)
end
end

View file

@ -1,2 +1,18 @@
module ApplicationHelper
def get_metacodeset
@m = user.settings.metacodes
set = @m[0].include?("metacodeset") ? MetacodeSet.find(@m[0].sub("metacodeset-","").to_i) : false
return set
end
def user_metacodes
@m = user.settings.metacodes
set = get_metacodeset
if set
@metacodes = set.metacodes
else
@metacodes = Metacode.where(id: @m).to_a
end
@metacodes.sort! {|m1,m2| m2.name.downcase <=> m1.name.downcase }.rotate!(-1)
end
end

View file

@ -1,5 +1,4 @@
class InMetacodeSet < ActiveRecord::Base
belongs_to :metacode, :class_name => "Metacode", :foreign_key => "metacode_id"
belongs_to :metacode_set, :class_name => "MetacodeSet", :foreign_key => "metacode_set_id"
# attr_accessible :title, :body
end

View file

@ -2,11 +2,10 @@ class Map < ActiveRecord::Base
belongs_to :user
has_many :topicmappings, :class_name => 'Mapping', :conditions => {:category => 'Topic'}
has_many :synapsemappings, :class_name => 'Mapping', :conditions => {:category => 'Synapse'}
has_many :topics, :through => :topicmappings
has_many :synapses, :through => :synapsemappings
has_many :topicmappings, -> { Mapping.topicmapping }, class_name: :Mapping, dependent: :destroy
has_many :synapsemappings, -> { Mapping.synapsemapping }, class_name: :Mapping, dependent: :destroy
has_many :topics, through: :topicmappings, source: :mappable, source_type: "Topic"
has_many :synapses, through: :synapsemappings, source: :mappable, source_type: "Synapse"
# This method associates the attribute ":image" with a file attachment
has_attached_file :screenshot, :styles => {

View file

@ -1,7 +1,10 @@
class Mapping < ActiveRecord::Base
belongs_to :topic, :class_name => "Topic", :foreign_key => "topic_id"
belongs_to :synapse, :class_name => "Synapse", :foreign_key => "synapse_id"
scope :topicmapping, -> { where(mappable_type: :Topic) }
scope :synapsemapping, -> { where(mappable_type: :Synapse) }
belongs_to :mappable, polymorphic: true
belongs_to :map, :class_name => "Map", :foreign_key => "map_id"
belongs_to :user

View file

@ -13,5 +13,4 @@ class Metacode < ActiveRecord::Base
return true if self.metacode_sets.include? metacode_set
return false
end
end

View file

@ -1,6 +1,5 @@
class MetacodeSet < ActiveRecord::Base
belongs_to :user
attr_accessible :desc, :mapperContributed, :name
has_many :in_metacode_sets
has_many :metacodes, :through => :in_metacode_sets
end

View file

@ -5,7 +5,7 @@ class Synapse < ActiveRecord::Base
belongs_to :topic1, :class_name => "Topic", :foreign_key => "node1_id"
belongs_to :topic2, :class_name => "Topic", :foreign_key => "node2_id"
has_many :mappings
has_many :mappings, as: :mappable, dependent: :destroy
has_many :maps, :through => :mappings
def user_name

View file

@ -3,12 +3,12 @@ class Topic < ActiveRecord::Base
belongs_to :user
has_many :synapses1, :class_name => 'Synapse', :foreign_key => 'node1_id'
has_many :synapses2, :class_name => 'Synapse', :foreign_key => 'node2_id'
has_many :synapses1, :class_name => 'Synapse', :foreign_key => 'node1_id', dependent: :destroy
has_many :synapses2, :class_name => 'Synapse', :foreign_key => 'node2_id', dependent: :destroy
has_many :topics1, :through => :synapses2, :source => :topic1
has_many :topics2, :through => :synapses1, :source => :topic2
has_many :mappings
has_many :mappings, as: :mappable, dependent: :destroy
has_many :maps, :through => :mappings
# This method associates the attribute ":image" with a file attachment

View file

@ -11,8 +11,6 @@ class User < ActiveRecord::Base
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :registerable
attr_accessible :name, :email, :image, :password, :password_confirmation, :code, :joinedwithcode, :remember_me
serialize :settings, UserPreference
validates :password, :presence => true,

View file

@ -129,7 +129,7 @@
<script type="text/template" id="mapSearchTemplate">
<div class="result{{rtype}}">
<div class="searchResIconWrapper">
<img class="icon" src="/assets/metamap36c.png">
<img class="icon" src="<%= asset_path('metamap36c.png') %>">
</div>
<div class="resultText">
<p class="resultTitle">{{label}}</p>
@ -196,6 +196,7 @@
</script>
<script type="text/template" id="topicAutocompleteTemplate">
<div>
<img class="autocompleteSection topicType" width="24" height="24" src="{{typeImageURL}}" alt="{{type}}" title="{{type}}" />
<p class="autocompleteSection topicTitle">{{label}}</p>
<div class="expandTopicMetadata"></div>
@ -209,6 +210,7 @@
<div class="topicPermission {{permission}}"></div>
</div>
<div class="clearfloat"></div>
</div>
</script>
@ -234,7 +236,7 @@
<div class="metacodeSelect">{{{metacode_select}}}</div>
</div>
<div class="linkItem contributor">
<a href="/explore/mapper/{{userid}}"><img src="/assets/user.png" class="contributorIcon" width="32" height="32" /></a>
<a href="/explore/mapper/{{userid}}"><img src="<%= asset_path('user.png') %>" class="contributorIcon" width="32" height="32" /></a>
<div class="contributorName">{{username}}</div>
</div>
<div class="linkItem mapCount">

View file

@ -8,12 +8,12 @@
<%= @map && @map.permission != 'private' ? " shareable" : "" %>">
<% if @map %>
<div class="mapInfoName" id="mapInfoName"><%= best_in_place @map, :name, :type => :textarea, :activator => "#mapInfoName", :classes => 'best_in_place_name' %></div>
<div class="mapInfoName" id="mapInfoName"><%= best_in_place @map, :name, :as => :textarea, :activator => "#mapInfoName", :class => 'best_in_place_name' %></div>
<div class="mapInfoStat">
<div class="infoStatIcon mapContributors hoverForTip">
<% if @map.contributors.count == 0 %>
<img id="mapContribs" width="25" height="25" src="/assets/user.png" />
<img id="mapContribs" width="25" height="25" src="<%= asset_path('user.png'); %>" />
<% elsif @map.contributors.count == 1 %>
<img id="mapContribs" width="25" height="25" src="<%= @map.contributors[0].image.url(:thirtytwo) %>" />
<% elsif @map.contributors.count == 2 %>
@ -42,7 +42,7 @@
<div class="mapInfoDesc" id="mapInfoDesc">
<% if (authenticated? && @map.authorize_to_edit(user)) || (!authenticated? && @map.desc != "" && @map.desc != nil )%>
<%= best_in_place @map, :desc, :activator => "#mapInfoDesc", :type => :textarea, :nil => "Click to add description...", :classes => 'best_in_place_desc' %>
<%= best_in_place @map, :desc, :activator => "#mapInfoDesc", :as => :textarea, :placeholder => "Click to add description...", :class => 'best_in_place_desc' %>
<% end %>
</div>

View file

@ -1,17 +1,8 @@
<%= form_for Topic.new, url: topics_url, remote: true do |form| %>
<div class="openMetacodeSwitcher openLightbox" data-open="switchMetacodes"></div>
<div id="metacodeImg">
<% @m = user.settings.metacodes %>
<% set = @m[0].include?("metacodeset") ? MetacodeSet.find(@m[0].sub("metacodeset-","").to_i) : false %>
<% if set %>
<% @metacodes = set.metacodes %>
<% else %>
<% @metacodes = [] %>
<% @m.each do |m| %>
<% @metacodes.push(Metacode.find(m.to_i)) %>
<% end %>
<% end %>
<% @metacodes.sort! {|m1,m2| m2.name.downcase <=> m1.name.downcase }.rotate!(-1) %>
<% @metacodes = user_metacodes() %>
<% set = get_metacodeset() %>
<% @metacodes.each do |metacode| %>
<img class="cloudcarousel" width="40" height="40" src="<%= metacode.icon %>" alt="<%= metacode.name %>" title="<%= metacode.name %>" data-id="<%= metacode.id %>" />
<% end %>

View file

@ -61,7 +61,7 @@
<span class="csTitle">Change Topic permission:</span> Click on 'Permission' icon (only for topic creator)
</div>
<div class="csItem indented">
<span class="csTitle">Open Topic view:</span> Click on <img src="/assets/synapse16.png" width="16" align="middle" /> icon within topic card bar
<span class="csTitle">Open Topic view:</span> Click on <img src="<%= asset_path('synapse16.png'); %>" width="16" align="middle" /> icon within topic card bar
</div>
<div class="csItem indented">
<span class="csTitle">Close 'Topic' card:</span> Click on canvas

View file

@ -76,7 +76,7 @@
@synapses.each_with_index do |synapse, index|
d = synapse.desc || ""
@synapselist += '<li data-id="' + d + '">'
@synapselist += '<img src="/assets/synapse16.png" alt="synapse icon" /><p>' + d
@synapselist += '<img src="' + asset_path('synapse16.png') + '" alt="synapse icon" /><p>' + d
@synapselist += '</p></li>'
end
@mappers.each_with_index do |mapper, index|

View file

@ -2,12 +2,7 @@ require File.expand_path('../boot', __FILE__)
require 'rails/all'
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require(*Rails.groups(:assets => %w(development test)))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
Bundler.require(:default, Rails.env)
module Metamaps
class Application < Rails::Application
@ -44,17 +39,12 @@ module Metamaps
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
# Enforce whitelist mode for mass assignment.
# This will create an empty whitelist of attributes available for mass-assignment for all models
# in your app. As such, your models will need to explicitly whitelist or blacklist accessible
# parameters by using an attr_accessible or attr_protected declaration.
# config.active_record.whitelist_attributes = true
# Enable the asset pipeline
config.assets.enabled = true
config.assets.initialize_on_precompile = false
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '2.0'
config.active_record.raise_in_transactional_callbacks = true
end
end

View file

@ -1,4 +1,12 @@
require 'rubygems'
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge(Host: '0.0.0.0', Port: 3000)
end
end
end
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)

View file

@ -1,14 +1,14 @@
Metamaps::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
config.log_level = :info
config.eager_load = false
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
@ -40,16 +40,6 @@ Metamaps::Application.configure do
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
# Raise exception on mass assignment protection for Active Record models
config.active_record.mass_assignment_sanitizer = :strict
# Log the query plan for queries taking more than this (works
# with SQLite, MySQL, and PostgreSQL)
config.active_record.auto_explain_threshold_in_seconds = 0.5
# Do not compress assets
config.assets.compress = false

View file

@ -1,6 +1,10 @@
Metamaps::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
config.log_level = :warn
config.eager_load = true
config.assets.js_compressor = :uglifier
# Code is not reloaded between requests
config.cache_classes = true
@ -9,7 +13,9 @@ Metamaps::Application.configure do
config.action_controller.perform_caching = true
# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = false
config.serve_static_files = true
config.assets.compile = true
# Compress JavaScripts and CSS
config.assets.compress = true

View file

@ -1,6 +1,8 @@
Metamaps::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
config.eager_load = false
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
@ -11,9 +13,6 @@ Metamaps::Application.configure do
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
# Log error messages when you accidentally call methods on nil
config.whiny_nils = true
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
@ -29,9 +28,6 @@ Metamaps::Application.configure do
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Raise exception on mass assignment protection for Active Record models
config.active_record.mass_assignment_sanitizer = :strict
# Print deprecation notices to the stderr
config.active_support.deprecation = :stderr
end

View file

@ -4,4 +4,4 @@
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
Metamaps::Application.config.secret_token = '267c8a84f63963282f45bc3010eaddf027abfab58fc759d6e239c8005f85ee99d6d01b1ab6394cdee9ca7f8c9213a0cf91d3d8d3350f096123e2caccbcc0924f'
Metamaps::Application.config.secret_key_base = '267c8a84f63963282f45bc3010eaddf027abfab58fc759d6e239c8005f85ee99d6d01b1ab6394cdee9ca7f8c9213a0cf91d3d8d3350f096123e2caccbcc0924f'

View file

@ -2,12 +2,12 @@ Metamaps::Application.routes.draw do
root to: 'main#home', via: :get
match 'request', to: 'main#requestinvite', via: :get, as: :request
get 'request', to: 'main#requestinvite', as: :request
match 'search/topics', to: 'main#searchtopics', via: :get, as: :searchtopics
match 'search/maps', to: 'main#searchmaps', via: :get, as: :searchmaps
match 'search/mappers', to: 'main#searchmappers', via: :get, as: :searchmappers
match 'search/synapses', to: 'main#searchsynapses', via: :get, as: :searchsynapses
get 'search/topics', to: 'main#searchtopics', as: :searchtopics
get 'search/maps', to: 'main#searchmaps', as: :searchmaps
get 'search/mappers', to: 'main#searchmappers', as: :searchmappers
get 'search/synapses', to: 'main#searchsynapses', as: :searchsynapses
resources :mappings, except: [:index, :new, :edit]
resources :metacode_sets, :except => [:show]
@ -16,28 +16,28 @@ Metamaps::Application.routes.draw do
resources :topics, except: [:index, :new, :edit] do
get :autocomplete_topic, :on => :collection
end
match 'topics/:id/network', to: 'topics#network', via: :get, as: :network
match 'topics/:id/relative_numbers', to: 'topics#relative_numbers', via: :get, as: :relative_numbers
match 'topics/:id/relatives', to: 'topics#relatives', via: :get, as: :relatives
get 'topics/:id/network', to: 'topics#network', as: :network
get 'topics/:id/relative_numbers', to: 'topics#relative_numbers', as: :relative_numbers
get 'topics/:id/relatives', to: 'topics#relatives', as: :relatives
match 'explore/active', to: 'maps#index', via: :get, as: :activemaps
match 'explore/featured', to: 'maps#index', via: :get, as: :featuredmaps
match 'explore/mine', to: 'maps#index', via: :get, as: :mymaps
match 'explore/mapper/:id', to: 'maps#index', via: :get, as: :usermaps
get 'explore/active', to: 'maps#index', as: :activemaps
get 'explore/featured', to: 'maps#index', as: :featuredmaps
get 'explore/mine', to: 'maps#index', as: :mymaps
get 'explore/mapper/:id', to: 'maps#index', as: :usermaps
resources :maps, except: [:new, :edit]
match 'maps/:id/contains', to: 'maps#contains', via: :get, as: :contains
match 'maps/:id/upload_screenshot', to: 'maps#screenshot', via: :post, as: :screenshot
get 'maps/:id/contains', to: 'maps#contains', as: :contains
get 'maps/:id/upload_screenshot', to: 'maps#screenshot', as: :screenshot
devise_for :users, controllers: { registrations: 'users/registrations', passwords: 'users/passwords', sessions: 'devise/sessions' }, :skip => [:sessions]
devise_for :users, controllers: { registrations: 'users/registrations', passwords: 'users/passwords', sessions: 'devise/sessions' }, :skip => :sessions
devise_scope :user do
get 'login' => 'devise/sessions#new', :as => :new_user_session
post 'login' => 'devise/sessions#create', :as => :user_session
get 'logout' => 'devise/sessions#destroy', :as => :destroy_user_session
get 'join' => 'devise/registrations#new', :as => :new_user_registration
get 'join' => 'devise/registrations#new', :as => :new_user_registration_path
end
match 'users/:id/details', to: 'users#details', via: :get, as: :details
match 'user/updatemetacodes', to: 'users#updatemetacodes', via: :post, as: :updatemetacodes
get 'users/:id/details', to: 'users#details', as: :details
post 'user/updatemetacodes', to: 'users#updatemetacodes', as: :updatemetacodes
resources :users, except: [:index, :destroy]
end

View file

@ -0,0 +1,31 @@
class MappingPolymorphism < ActiveRecord::Migration
def up
add_column :mappings, :mappable_id, :integer
add_column :mappings, :mappable_type, :string
add_index :mappings, [:mappable_id, :mappable_type]
Mapping.find_each do |mapping|
if mapping.synapse_id.nil? and mapping.topic_id.nil?
puts "Mapping id=#{mapping.id} has no valid id, skipping!"
next
end
if not mapping.synapse_id.nil? and not mapping.topic_id.nil?
puts "Mapping id=#{mapping.id} has both topic and synapse ids, skipping!"
next
end
unless mapping.synapse_id.nil?
mapping.mappable = Synapse.find(mapping.synapse_id)
else
mapping.mappable = Topic.find(mapping.topic_id)
end
mapping.save
end
end
def down
remove_index :mappings, [:mappable_id, :mappable_type]
remove_column :mappings, :mappable_id, :integer
remove_column :mappings, :mappable_type, :string
end
end

View file

@ -9,21 +9,24 @@
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended to check this file into your version control system.
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(:version => 20141121204712) do
ActiveRecord::Schema.define(version: 20151001024122) do
create_table "in_metacode_sets", :force => true do |t|
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "in_metacode_sets", force: :cascade do |t|
t.integer "metacode_id"
t.integer "metacode_set_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "in_metacode_sets", ["metacode_id"], :name => "index_in_metacode_sets_on_metacode_id"
add_index "in_metacode_sets", ["metacode_set_id"], :name => "index_in_metacode_sets_on_metacode_set_id"
add_index "in_metacode_sets", ["metacode_id"], name: "index_in_metacode_sets_on_metacode_id", using: :btree
add_index "in_metacode_sets", ["metacode_set_id"], name: "index_in_metacode_sets_on_metacode_set_id", using: :btree
create_table "mappings", :force => true do |t|
create_table "mappings", force: :cascade do |t|
t.text "category"
t.integer "xloc"
t.integer "yloc"
@ -31,18 +34,22 @@ ActiveRecord::Schema.define(:version => 20141121204712) do
t.integer "synapse_id"
t.integer "map_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "mappable_id"
t.string "mappable_type"
end
create_table "maps", :force => true do |t|
add_index "mappings", ["mappable_id", "mappable_type"], name: "index_mappings_on_mappable_id_and_mappable_type", using: :btree
create_table "maps", force: :cascade do |t|
t.text "name"
t.boolean "arranged"
t.text "desc"
t.text "permission"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "featured"
t.string "screenshot_file_name"
t.string "screenshot_content_type"
@ -50,26 +57,26 @@ ActiveRecord::Schema.define(:version => 20141121204712) do
t.datetime "screenshot_updated_at"
end
create_table "metacode_sets", :force => true do |t|
create_table "metacode_sets", force: :cascade do |t|
t.string "name"
t.text "desc"
t.integer "user_id"
t.boolean "mapperContributed"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "metacode_sets", ["user_id"], :name => "index_metacode_sets_on_user_id"
add_index "metacode_sets", ["user_id"], name: "index_metacode_sets_on_user_id", using: :btree
create_table "metacodes", :force => true do |t|
create_table "metacodes", force: :cascade do |t|
t.text "name"
t.string "icon"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "color"
end
create_table "synapses", :force => true do |t|
create_table "synapses", force: :cascade do |t|
t.text "desc"
t.text "category"
t.text "weight"
@ -77,19 +84,19 @@ ActiveRecord::Schema.define(:version => 20141121204712) do
t.integer "node1_id"
t.integer "node2_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "topics", :force => true do |t|
create_table "topics", force: :cascade do |t|
t.text "name"
t.text "desc"
t.text "link"
t.text "permission"
t.integer "user_id"
t.integer "metacode_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
@ -100,25 +107,25 @@ ActiveRecord::Schema.define(:version => 20141121204712) do
t.datetime "audio_updated_at"
end
create_table "users", :force => true do |t|
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.text "settings"
t.string "code", :limit => 8
t.string "joinedwithcode", :limit => 8
t.string "code", limit: 8
t.string "joinedwithcode", limit: 8
t.string "crypted_password"
t.string "password_salt"
t.string "persistence_token"
t.string "perishable_token"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "encrypted_password", :limit => 128, :default => ""
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "encrypted_password", limit: 128, default: ""
t.string "remember_token"
t.datetime "remember_created_at"
t.string "reset_password_token"
t.datetime "last_sign_in_at"
t.string "last_sign_in_ip"
t.integer "sign_in_count", :default => 0
t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.string "current_sign_in_ip"
t.datetime "reset_password_sent_at"
@ -130,6 +137,6 @@ ActiveRecord::Schema.define(:version => 20141121204712) do
t.integer "generation"
end
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end

24
metamaps-qa-steps.txt Normal file
View file

@ -0,0 +1,24 @@
Metamaps Test Suite
1) Log in to the interface
2) Create an account using your join code
3) Check your user's "generation"
4) Create three maps: private, public, and another public
5) Change the last map's permissions to commons
6) Change a map's name
7) Create a topic on map #1
8) Verify (in a private window or another browser) that the second user can't acccess map #1
9) Create a topic on map #2
10) Verify that the second user can't edit map #2
11) Create a topic on map #3
12) Verify that the second can edit map #3
13) Pull a topic from map #1 to map #3
14) Create a private topic on map #1
15) Verify that the private topic can be pulled from map #1 by the same user
16) Verify that the private topic can't be pulled from map #1 by another user
17) Login as admin. Change metacode sets.
18) Add a number of topics to one of your maps. Reload to see if they are still there.
19) Add a number of synapses to one of your maps. Reload to see if they are still there.
20) Rearrange one of your maps. Reload to see if the layout is preserved.
21) Set the screenshot for one of your maps, and verify the index of maps is updated.
22) Open two browsers on map #3 and verify that realtime editing works.