Skip to content

Commit

Permalink
Map Popups (#7715)
Browse files Browse the repository at this point in the history
* add more info to map popups

* format popup with options and css, limit title length

* map popup formatting

* add # link to wiki popups

* update inline map unit tests with new classes

* update test to remove tags from wiki to fix error

* add created_at and doc_image_url to nearbyPeople search

* fix test error from new tags

* fix test errors

* fix lint errors

* adjust test for returns wikis updated

* Fixing Travis system testing

* Removing unwanted screenshot logging

Co-authored-by: Natalie <[email protected]>
  • Loading branch information
alaxalves and nstjean authored Mar 26, 2020
1 parent 4bf071e commit 668c28e
Show file tree
Hide file tree
Showing 17 changed files with 205 additions and 79 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ env:
- CI=true
- GENERATE_REPORT=true
- RAILS_ENV=test
- RAILS_SYSTEM_TESTING_SCREENSHOT=simple

before_install:
- sudo wget https://chromedriver.storage.googleapis.com/73.0.3683.68/chromedriver_linux64.zip
Expand Down Expand Up @@ -58,7 +59,7 @@ jobs:
- name: "Integration Tests"
script: bundle exec rails test test/integration
- name: "System Tests"
script: bundle exec rails test:system > /dev/null
script: bundle exec rails test:system

after_script:
- echo -e '<?xml version="1.0" encoding="UTF-8"?>' > output.xml;
Expand Down
14 changes: 11 additions & 3 deletions app/api/srch/search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -311,17 +311,23 @@ class Search < Grape::API

if results.present?
docs = results.map do |model|
doctype = model.has_power_tag('question') ? 'QUESTION' : 'NOTE'
doctype = 'WIKI' if model.type == 'page'
DocResult.new(
doc_id: model.nid,
doc_type: 'PLACES',
doc_type: doctype,
doc_url: model.path(:items),
doc_title: model.title,
doc_author: model.user.username,
doc_image_url: !model.images.empty? ? model.images.first.path : 0,
score: model.answers.length,
latitude: model.lat,
longitude: model.lon,
blurred: model.blurred?
blurred: model.blurred?,
place_name: model.has_power_tag('place') ? model.power_tag('place') : '',
created_at: model.created_at,
# time_since: distance_of_time_in_words(model.created_at, Time.current, { include_seconds: false, scope: 'datetime.time_ago_in_words' }), # works, but really slows down the search results
# comment_count: model.comments_viewable_by(current_user).length # causes an error because of current_user?
)
end
DocList.new(docs, search_request)
Expand Down Expand Up @@ -350,7 +356,9 @@ class Search < Grape::API
doc_title: model.username,
latitude: model.lat,
longitude: model.lon,
blurred: model.blurred?
blurred: model.blurred?,
created_at: model.created_at,
doc_image_url: model.profile_image ? model.profile_image : ""
)
end
DocList.new(docs, search_request)
Expand Down
3 changes: 2 additions & 1 deletion app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,5 @@
//= require jquery-validation/dist/jquery.validate.js
//= require validation.js
//= require submit_form_ajax.js
//= require urlMapHash.js
//= require urlMapHash.js
//= require timeago.js
92 changes: 58 additions & 34 deletions app/assets/javascripts/leaflet_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
return map ;
}

function PLmarker_default(){
function PLmarker_default(color = 'black'){
// valid colors: blue, gold, green, orange, yellow, violet, grey, black
L.Icon.PLmarker = L.Icon.extend({
options: {
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-black.png',
iconUrl: 'https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-'+color+'.png',
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
Expand Down Expand Up @@ -51,42 +52,65 @@
}

function contentLayerParser(map, markers_hash, map_tagname) {
var NWlat = map.getBounds().getNorthWest().lat ;
var NWlng = map.getBounds().getNorthWest().lng ;
var SElat = map.getBounds().getSouthEast().lat ;
var SElng = map.getBounds().getSouthEast().lng ;
map.spin(true) ;
var NWlat = map.getBounds().getNorthWest().lat ;
var NWlng = map.getBounds().getNorthWest().lng ;
var SElat = map.getBounds().getSouthEast().lat ;
var SElng = map.getBounds().getSouthEast().lng ;
map.spin(true) ;

if(map_tagname === null || (typeof map_tagname === "undefined")) {
taglocation_url = "/api/srch/taglocations?nwlat=" + NWlat + "&selat=" + SElat + "&nwlng=" + NWlng + "&selng=" + SElng ;
if(map_tagname === null || (typeof map_tagname === "undefined")) {
taglocation_url = "/api/srch/taglocations?nwlat=" + NWlat + "&selat=" + SElat + "&nwlng=" + NWlng + "&selng=" + SElng ;

} else {
taglocation_url = "/api/srch/taglocations?nwlat=" + NWlat + "&selat=" + SElat + "&nwlng=" + NWlng + "&selng=" + SElng + "&tag=" + map_tagname ;
}
$.getJSON(taglocation_url , function (data) {
if (!!data.items) {
for (i = 0; i < data.items.length; i++) {
var url = data.items[i].doc_url;
var title = data.items[i].doc_title;
var author = data.items[i].doc_author;
var image_url = data.items[i].doc_image_url;
var default_url = PLmarker_default();
var mid = data.items[i].doc_id ;
var m = L.marker([data.items[i].latitude, data.items[i].longitude], {icon: default_url}).bindPopup("<a href=" + url + ">" + title + "</a>") ;

if(markers_hash.has(mid) === false){
} else {
taglocation_url = "/api/srch/taglocations?nwlat=" + NWlat + "&selat=" + SElat + "&nwlng=" + NWlng + "&selng=" + SElng + "&tag=" + map_tagname ;
}

if(image_url) {
m.addTo(map).bindPopup("<div><img src=" + image_url+ " height='140px' /><br>" + "<b>Title:</b> " + title + "<br><b>Author:</b> <a href=" + 'https://publiclab.org/profile/' + author + ">" + author + "</a><br>" + "<a href=" + url + ">" + "Read more..." + "</a></div>" ) ;
} else {
m.addTo(map).bindPopup("<span><b>Title:</b> " + title + "</span><br><span><b>Author:</b> <a href=" + 'https://publiclab.org/profile/' + author + ">" + author + "</a></span><br>" + "<a href=" + url + ">" + "<br>Read more..." + "</a>" ) ;
}
markers_hash.set(mid , m) ;
}
$.getJSON(taglocation_url , function (data) {
if (!!data.items) {
for (i = 0; i < data.items.length; i++) {
var nodetype = data.items[i].doc_type;
nodetype = nodetype.charAt(0).toUpperCase() + nodetype.slice(1).toLowerCase();

var place_name = data.items[i].place_name;
var url = data.items[i].doc_url;
var title = data.items[i].doc_title;
var author = data.items[i].doc_author;
var image_url = data.items[i].doc_image_url;
var map_marker = PLmarker_default('blue');
var mid = data.items[i].doc_id;
var created_at = data.items[i].created_at;
var time_since = TimeAgo().inWords(new Date(data.items[i].created_at));
// var comment_count = data.items[i].comment_count;

var m = L.marker([data.items[i].latitude, data.items[i].longitude], {icon: map_marker});

if(markers_hash.has(mid) === false){
var popup_content = "";
if (image_url) popup_content += "<img src='" + image_url + "' class='popup-thumb' />";
popup_content += "<h5><a href='" + url + "'>" + limit_words(title, 10) + "</a></h5>";
popup_content += "<div class='popup-two-column'>";
popup_content += "<div class='popup-stretch-column'>" + nodetype + " by <a href='https://publiclab.org/profile/" + author + "'>@" + author + "</a> " + time_since + "</div><br>";
if (nodetype.toLowerCase() === "wiki") popup_content += "<div class='map-slug popup-shrink-column'><a href='/map/" + url.split('/').pop() + "'>#</a></div>";
popup_content += "</div>";
// if (place_name) popup_content += "<span><b>Place: </b>" + place_name + "</span><br>";

var popup = L.popup({
maxWidth: 300,
autoPan: false,
className: 'map-popup'
}).setContent(popup_content);
m.addTo(map).bindPopup(popup_content);

markers_hash.set(mid , m) ;
}
}
map.spin(false) ;
});
}
}
map.spin(false) ;
});

function limit_words(str, num_words) {
return str.split(" ").splice(0, num_words).join(" ");
}
}

function setupLEL(map, markers_hash = null, params = {}) {
Expand Down
63 changes: 63 additions & 0 deletions app/assets/javascripts/timeago.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Function by caiotarifa: https://gist.github.com/caiotarifa/30ae974f2293c761f3139dd194abd9e5
//
// using this function instead of distance_of_time_in_words in Ruby for the map popups calculation in leaflet_helper.js

var TimeAgo = (function() {
var self = {};

// Public Methods
self.locales = {
prefix: '',
sufix: 'ago',

seconds: '1 minute',
minute: '1 minute',
minutes: '%d minutes',
hour: '1 hour',
hours: '%d hours',
day: '1 day',
days: '%d days',
month: '1 month',
months: '%d months',
year: '1 year',
years: '%d years'
};

self.inWords = function(timeAgo) {

var seconds = Math.floor((new Date() - new Date(timeAgo)) / 1000),
separator = this.locales.separator || ' ',
words = this.locales.prefix + separator,
interval = 0,
intervals = {
year: seconds / 31536000,
month: seconds / 2592000,
day: seconds / 86400,
hour: seconds / 3600,
minute: seconds / 60
};

var distance = this.locales.seconds;

for (var key in intervals) {
if (intervals.hasOwnProperty(key)) {
interval = Math.floor(intervals[key]);

if (interval > 1) {
distance = this.locales[key + 's'];
break;
} else if (interval === 1) {
distance = this.locales[key];
break;
}
}
}

distance = distance.replace(/%d/i, interval);
words += distance + separator + this.locales.sufix;

return words.trim();
};

return self;
}());
25 changes: 22 additions & 3 deletions app/assets/stylesheets/map.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,26 @@
.leaflet-top{
z-index:800 !important;
}
.leaflet-popup-content {
width: 800px !important;
.leaflet-popup .leaflet-popup-content {
width: 300px;
max-width: 300px;
margin: 15px;
}

.leaflet-popup .leaflet-popup-content img.popup-thumb {
width: 100%;
margin-bottom: 15px;
}
.leaflet-popup .leaflet-popup-content h5 {
margin-bottom: 4px;
}
.leaflet-popup .popup-two-column {
display: flex;
width: 100%;
justify-content: space-between;
}
.leaflet-popup .popup-stretch-column {
flex: 1 1 100%;
}
.leaflet-popup .popup-shrink-column {
flex: 0 1 auto;
}
10 changes: 9 additions & 1 deletion app/models/doc_result.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# A DocResult is an individual return item for a document (web page) search
class DocResult
attr_accessor :doc_id, :doc_type, :doc_url, :doc_title, :doc_score, :latitude, :longitude, :blurred, :category, :doc_author, :doc_image_url
attr_accessor :doc_id, :doc_type, :doc_url, :doc_title, :doc_score, :latitude, :longitude, :blurred, :category, :doc_author, :doc_image_url, :place_name, :created_at, :comment_count, :time_since, :user_photo_path

def initialize(args = {})
@doc_id = args[:doc_id]
Expand All @@ -14,6 +14,10 @@ def initialize(args = {})
@longitude = args[:longitude]
@blurred = args[:blurred]
@category = args[:doc_type]
@place_name = args[:place_name]
@created_at = args[:created_at]
@time_since = args[:time_since]
@comment_count = args[:comment_count]
end

# This subclass is used to auto-generate the RESTful data structure. It is generally not useful for internal Ruby usage
Expand All @@ -26,5 +30,9 @@ class Entity < Grape::Entity
expose :doc_score, documentation: { type: 'Float', desc: "If calculated, the relevance of the document result to the search request; i.e. the 'matching score'" }
expose :latitude, documentation: { type: 'String', desc: "Returns the latitude associated with the node." }
expose :longitude, documentation: { type: 'String', desc: "Returns the longitude associated with the node." }
expose :place_name, documentation: { type: 'String', desc: "Returns the place name of the location associated with the node." }
expose :created_at, documentation: { type: 'String', desc: "Returns the date the node was created." }
expose :time_since, documentation: { type: 'String', desc: "Returns a description of the amount of time that has passed since the node was created." }
expose :comment_count, documentation: { type: 'String', desc: "Returns the number of comments the user can view belonging to the node." }
end
end
5 changes: 1 addition & 4 deletions app/views/map/_inlineLeaflet.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
#postOnMap<%= unique_id %> {
margin-top: 5px;
}
.leaflet-popup-content {
width: auto !important;
}
a.grid-embed {
float:right;
padding:8px;
Expand All @@ -17,7 +14,7 @@
}
</style>

<div class="leaflet-map inline-fullwidth-content" id="map<%= unique_id %>"></div>
<div class="leaflet-map inline-map inline-fullwidth-content" id="map<%= unique_id %>"></div>

<a id="iframeID<%= unique_id %>" class="grid-embed" rel="tooltip" title="Embed this map on another site."><i class="fa fa-code" style="color:#aaa;"></i></a>

Expand Down
2 changes: 1 addition & 1 deletion app/views/map/_leaflet.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<style>
#map<%= unique_id %> { width:100%; height:300px; margin: 0; position: relative;}
</style>
<div class="leaflet-map" id="map<%= unique_id %>"></div>
<div class="leaflet-map sidebar-top-map" id="map<%= unique_id %>"></div>
<% if defined? people %><p><i><small>Share your own location on <a href='/profile'>your profile</a>.</small></i></p><% end %>
<% end %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/map/_peopleLeaflet.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</style>

<div>
<div class="leaflet-map" id="map<%= unique_id %>"></div>
<div class="leaflet-map inline-map" id="map<%= unique_id %>"></div>
</div>

<p><i><small>
Expand Down
5 changes: 1 addition & 4 deletions app/views/map/_plainInlineLeaflet.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@
#postOnMap<%= unique_id %> {
margin-top: 5px;
}
.leaflet-popup-content {
width: auto !important;
}
</style>
<div class="inline-fullwidth-content">
<div class="leaflet-map" id="map<%= unique_id %>"></div>
<div class="leaflet-map inline-map" id="map<%= unique_id %>"></div>
</div>


Expand Down
18 changes: 18 additions & 0 deletions test/fixtures/node_tags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,21 @@ test4_zoom:
uid: 1
nid: 7
date: <%= DateTime.now.to_i %>

organizers-awesome:
tid: 2
uid: 2
nid: 5
date: <%= DateTime.now.to_i %>

organizers-everything:
tid: 4
uid: 2
nid: 5
date: <%= DateTime.now.to_i %>

organizers-chapter:
tid: 5
uid: 2
nid: 5
date: <%= DateTime.now.to_i %>
2 changes: 1 addition & 1 deletion test/functional/tag_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ def setup

assert_response :success
assert_select 'table' # ensure a table is shown
assert_equal 3, css_select('tr').length # ensure it has 3 rows
assert_equal 4, css_select('tr').length # ensure it has 4 rows
end

test 'rss with tagname and authorname' do
Expand Down
3 changes: 0 additions & 3 deletions test/system/map_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ class MapTest < ApplicationSystemTestCase
page.execute_script("map.setView([13, 60], 15)")
url_hash = page.evaluate_script("window.location.hash")

# Wait for any potential asynchronous operations to complete
wait_for_ajax

# check that the url hash is correct
assert_equal("#15/13/60", url_hash)
end
Expand Down
Loading

0 comments on commit 668c28e

Please sign in to comment.