blacklight-maps 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +18 -0
  4. data/Gemfile +16 -0
  5. data/LICENSE.txt +13 -0
  6. data/README.md +81 -0
  7. data/Rakefile +43 -0
  8. data/app/assets/javascripts/blacklight-maps.js +8 -0
  9. data/app/assets/javascripts/blacklight-maps/blacklight-maps-browse.js +141 -0
  10. data/app/assets/stylesheets/blacklight_maps/blacklight-maps.css.scss +4 -0
  11. data/app/assets/stylesheets/blacklight_maps/default.css.scss +24 -0
  12. data/app/helpers/blacklight_maps_helper.rb +36 -0
  13. data/app/views/catalog/_document_maps.html.erb +6 -0
  14. data/app/views/catalog/_index_maps.html.erb +9 -0
  15. data/blacklight-maps.gemspec +34 -0
  16. data/config/jetty.yml +7 -0
  17. data/config/locales/blacklight-maps.en.yml +5 -0
  18. data/config/routes.rb +4 -0
  19. data/docs/map-sidebar.png +0 -0
  20. data/docs/map-view.png +0 -0
  21. data/lib/blacklight/maps.rb +7 -0
  22. data/lib/blacklight/maps/engine.rb +32 -0
  23. data/lib/blacklight/maps/version.rb +5 -0
  24. data/lib/generators/blacklight_maps/install_generator.rb +25 -0
  25. data/lib/generators/blacklight_maps/templates/blacklight_maps.css.scss +3 -0
  26. data/lib/railties/blacklight_maps.rake +13 -0
  27. data/solr_conf/conf/schema.xml +673 -0
  28. data/solr_conf/conf/solrconfig.xml +523 -0
  29. data/spec/features/maps_spec.rb +79 -0
  30. data/spec/fixtures/sample_solr_documents.yml +2742 -0
  31. data/spec/helpers/blacklight_maps_helper_spec.rb +28 -0
  32. data/spec/spec_helper.rb +38 -0
  33. data/spec/test_app_templates/Gemfile.extra +7 -0
  34. data/spec/test_app_templates/lib/generators/test_app_generator.rb +23 -0
  35. metadata +268 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e35e471feb601eeeec9355dc1cc7e31d158f03bb
4
+ data.tar.gz: 8be5024c30a03decfb0e15563f79117606be1fec
5
+ SHA512:
6
+ metadata.gz: b019eae752da2b6cc576a759b09abb1d7799748c82603b0d13f20990f592e0ad51b35785abb6dda9370d5cbbd477c506ee26db9f73ae2cfa8aa7380ea584c707
7
+ data.tar.gz: a999abc043657b6f52ae34f1ce6d5479491b49812e2fa87b93257a3173de069a4e237d09e4cfb53869849d939803554842a918aec59e78c182d94be3d02f787b
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ spec/internal
19
+ jetty
20
+ .DS_Store
data/.travis.yml ADDED
@@ -0,0 +1,18 @@
1
+ notifications:
2
+ email: false
3
+
4
+ rvm:
5
+ - 2.1.0
6
+ - 2.0.0
7
+ - 1.9.3
8
+ - jruby-19mode
9
+
10
+ notifications:
11
+ irc: "irc.freenode.org#blacklight"
12
+ email:
13
+ - blacklight-commits@googlegroups.com
14
+
15
+ env:
16
+ global:
17
+ - JRUBY_OPTS="-J-Xms512m -J-Xmx1024m"
18
+ - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in blacklight-maps.gemspec
4
+ gemspec
5
+
6
+ gem 'simplecov', require: false
7
+ gem 'coveralls', require: false
8
+
9
+ gem 'engine_cart', git: 'https://github.com/cbeer/engine_cart'
10
+
11
+
12
+ file = File.expand_path("Gemfile", ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path("../spec/internal", __FILE__))
13
+ if File.exists?(file)
14
+ puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
15
+ instance_eval File.read(file)
16
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2014 The Board of Trustees of the Leland Stanford Junior University.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # Blacklight::Maps
2
+
3
+ [![Build Status](https://travis-ci.org/sul-dlss/blacklight-maps.png?branch=master)](https://travis-ci.org/sul-dlss/blacklight-maps)
4
+
5
+ Provides a map view for Blacklight search results.
6
+
7
+ ![Screen shot](docs/map-view.png)
8
+ ![Screen shot](docs/map-sidebar.png)
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'blacklight-maps'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install blacklight-maps
23
+
24
+ ## Usage
25
+
26
+ Blacklight-Maps adds a map view capability for a results set that contains geospatial coordinates (latitude/longitude).
27
+
28
+ For now, Blacklight-Maps requires that your SOLR index includes a field containing placenames with latitude and longitude coordinates delimited by `|`. This field can be multivalued.
29
+
30
+ A document requires the following field:
31
+ ```
32
+ placename_coords:
33
+ - China|35.86166|104.195397
34
+ - Tibet|29.646923|91.117212
35
+ - India|20.593684|78.96288
36
+ ```
37
+
38
+ Note: We are looking at implementing support for additional fields.
39
+
40
+ ### Configuration
41
+
42
+ #### Required
43
+ Blacklight-Maps expects you to provide:
44
+
45
+ - a field to map the placename coordinates (`placename_coords` in the example above)
46
+
47
+ #### Optional
48
+
49
+ - the maxZoom [property of the map](http://leafletjs.com/reference.html#map-maxzoom)
50
+ - a [tileLayer url](http://leafletjs.com/reference.html#tilelayer-l.tilelayer) to change the basemap
51
+ - an [attribution string](http://leafletjs.com/reference.html#tilelayer-attribution) to describe the basemap layer
52
+
53
+
54
+ All of these options can easily be configured in `CatalogController.rb` in the `config` block.
55
+
56
+ ```
57
+ ...
58
+ configure_blacklight do |config|
59
+ ## Default parameters to send to solr for all search-like requests. See also SolrHelper#solr_search_params
60
+ config.default_solr_params = {
61
+ :qt => 'search',
62
+ :rows => 10,
63
+ :fl => '*'
64
+ }
65
+
66
+ ## Default values
67
+ config.view.maps.placename_coords_field = "placename_coords"
68
+ config.view.maps.tileurl = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
69
+ config.view.maps.attribution = 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'
70
+ ...
71
+
72
+ ```
73
+
74
+
75
+ ## Contributing
76
+
77
+ 1. Fork it ( http://github.com/<my-github-username>/blacklight-maps/fork )
78
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
79
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
80
+ 4. Push to the branch (`git push origin my-new-feature`)
81
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ ZIP_URL = "https://github.com/projectblacklight/blacklight-jetty/archive/v4.6.0.zip"
4
+ APP_ROOT = File.dirname(__FILE__)
5
+
6
+ require 'rspec/core/rake_task'
7
+ require 'engine_cart/rake_task'
8
+
9
+ require 'jettywrapper'
10
+
11
+ task default: :ci
12
+
13
+ RSpec::Core::RakeTask.new(:spec)
14
+
15
+ desc "Load fixtures"
16
+ task :fixtures => ['engine_cart:generate'] do
17
+ EngineCart.within_test_app do
18
+ system "rake blacklight_maps:solr:seed RAILS_ENV=test"
19
+ end
20
+ end
21
+
22
+ desc "Execute Continuous Integration build"
23
+ task :ci => ['engine_cart:generate', 'jetty:clean', 'blacklight_maps:configure_jetty'] do
24
+
25
+ require 'jettywrapper'
26
+ jetty_params = Jettywrapper.load_config('test')
27
+
28
+ error = Jettywrapper.wrap(jetty_params) do
29
+ Rake::Task['fixtures'].invoke
30
+ Rake::Task['spec'].invoke
31
+ end
32
+ raise "test failures: #{error}" if error
33
+ end
34
+
35
+
36
+ namespace :blacklight_maps do
37
+ desc "Copies the default SOLR config for the bundled Testing Server"
38
+ task :configure_jetty do
39
+ FileList['solr_conf/conf/*'].each do |f|
40
+ cp("#{f}", 'jetty/solr/blacklight-core/conf/', :verbose => true)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,8 @@
1
+ // for Blacklight.onLoad:
2
+ //= require blacklight/core
3
+
4
+ //= require leaflet
5
+ //= require leaflet.markercluster
6
+ //= require L.Control.Sidebar
7
+
8
+ //= require_tree './blacklight-maps'
@@ -0,0 +1,141 @@
1
+ var map, sidebar;
2
+
3
+ Blacklight.onLoad(function() {
4
+
5
+ // Stop doing stuff if the map div isn't there
6
+ if ($("#blacklight-map").length === 0){
7
+ return;
8
+ }
9
+
10
+ // Get the configuration options from the data-attributes
11
+ $.extend(Blacklight.mapOptions, $("#blacklight-map").data());
12
+
13
+ map = L.map('blacklight-map').setView([0,0], 2);
14
+ L.tileLayer(Blacklight.mapOptions.tileurl, {
15
+ attribution: Blacklight.mapOptions.mapattribution,
16
+ maxZoom: Blacklight.mapOptions.maxzoom
17
+ }).addTo(map);
18
+
19
+ // Sets up leaflet-sidebar
20
+ sidebar = L.control.sidebar('blacklight-map-sidebar', {
21
+ position: 'right',
22
+ autoPan: false
23
+ });
24
+
25
+ // Adds leaflet-sidebar control to map (object)
26
+ map.addControl(sidebar);
27
+
28
+ // Create a marker cluster object and set options
29
+ markers = new L.MarkerClusterGroup({
30
+ showCoverageOnHover: false,
31
+ spiderfyOnMaxZoom: false,
32
+ singleMarkerMode: true,
33
+ animateAddingMarkers: true
34
+ });
35
+
36
+ geoJsonLayer = L.geoJson(geojson_docs, {
37
+ onEachFeature: function(feature, layer){
38
+ layer.defaultOptions.title = feature.properties.placename;
39
+ layer.on('click', function(e){
40
+ if (sidebar.isVisible()){
41
+ sidebar.hide();
42
+ }
43
+ var placenames = {};
44
+ placenames[feature.properties.placename] = [feature.properties.html];
45
+ offsetMap(e);
46
+ $('#blacklight-map-sidebar').html(buildList(placenames));
47
+ sidebar.show();
48
+ });
49
+ }
50
+ });
51
+
52
+ // Add GeoJSON layer to marker cluster object
53
+ markers.addLayer(geoJsonLayer);
54
+
55
+ // Add marker cluster object to map
56
+ map.addLayer(markers);
57
+
58
+ // Listeners for marker cluster clicks
59
+ markers.on('clusterclick', function(e){
60
+
61
+ //hide sidebar if it is visible
62
+ if (sidebar.isVisible()){
63
+ sidebar.hide();
64
+ }
65
+
66
+ //if map is at the lowest zoom level
67
+ if (map.getZoom() === Blacklight.mapOptions.maxzoom){
68
+
69
+ var placenames = generatePlacenamesObject(e.layer._markers);
70
+
71
+
72
+ offsetMap(e);
73
+
74
+ //Update sidebar div with new html
75
+ $('#blacklight-map-sidebar').html(buildList(placenames));
76
+
77
+ //Show the sidebar!
78
+ sidebar.show();
79
+ }
80
+ });
81
+
82
+ //Add click listener to map
83
+ map.on('click', function(e){
84
+
85
+ //hide the sidebar if it is visible
86
+ if (sidebar.isVisible()){
87
+ sidebar.hide();
88
+ }
89
+ });
90
+
91
+ //drag listener on map
92
+ map.on('drag', function(e){
93
+
94
+ //hide the sidebar if it is visible
95
+ if (sidebar.isVisible()){
96
+ sidebar.hide();
97
+ }
98
+ });
99
+
100
+ });
101
+
102
+ Blacklight.mapOptions = {
103
+ tileurl : 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
104
+ mapattribution : 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'
105
+ };
106
+
107
+ function buildList(placenames){
108
+ var html = "";
109
+ $.each(placenames, function(i,val){
110
+ html += "<h2>" + i + "</h2>";
111
+ html += "<ul class='sidebar-list'>";
112
+ $.each(val, function(j, val2){
113
+ html += val2;
114
+ });
115
+ html += "</ul>";
116
+ });
117
+ return html;
118
+ }
119
+
120
+ // Generates placenames object
121
+ function generatePlacenamesObject(markers){
122
+ var placenames = {};
123
+ $.each(markers, function(i,val){
124
+ if (!(val.feature.properties.placename in placenames)){
125
+ placenames[val.feature.properties.placename] = [];
126
+ }
127
+ placenames[val.feature.properties.placename].push(val.feature.properties.html);
128
+ });
129
+ return placenames;
130
+ }
131
+
132
+ // Move the map so that it centers the clicked cluster TODO account for various size screens
133
+ function offsetMap(e){
134
+ mapWidth = $('#blacklight-map').width();
135
+ mapHeight = $('#blacklight-map').height();
136
+ if (!e.latlng.equals(map.getCenter())){
137
+ map.panBy([(e.originalEvent.layerX - (mapWidth/4)), (e.originalEvent.layerY - (mapHeight/2))]);
138
+ }else{
139
+ map.panBy([(mapWidth/4), 0]);
140
+ }
141
+ }
@@ -0,0 +1,4 @@
1
+ /* Master manifest file for engine, so local app can require
2
+ * this one file, but get all our files -- and local app
3
+ * require does not need to change if we change file list.
4
+ */
@@ -0,0 +1,24 @@
1
+ /*
2
+ *= require leaflet
3
+ *= require leaflet.markercluster
4
+ *= require leaflet.markercluster.default
5
+ *= require L.Control.Sidebar.css
6
+ */
7
+
8
+ .view-icon-maps {
9
+ &:before { content: "\e135"; }
10
+ }
11
+
12
+ #blacklight-map{
13
+ height: 550px;
14
+ }
15
+
16
+ .sidebar-thumb{
17
+ height: 64px;
18
+ width: 64px;
19
+ }
20
+
21
+ .sidebar-list{
22
+ padding-left: 0;
23
+ list-style: none;
24
+ }
@@ -0,0 +1,36 @@
1
+ module BlacklightMapsHelper
2
+
3
+ def show_map_div
4
+ data_attributes = {
5
+ :maxzoom => blacklight_config.view.maps.maxzoom,
6
+ :tileurl => blacklight_config.view.maps.tileurl
7
+
8
+ }
9
+
10
+ content_tag(:div, "", id: "blacklight-map",
11
+ data: data_attributes
12
+ )
13
+ end
14
+
15
+ def serialize_geojson
16
+ geojson_docs = {type: "FeatureCollection", features: []}
17
+ @response.docs.each_with_index do |doc, counter|
18
+ if doc[blacklight_config.view.maps.placename_coord_field]
19
+ doc[blacklight_config.view.maps.placename_coord_field].each do |loc|
20
+ values = loc.split('|')
21
+ feature = {type: "Feature", geometry: {type: "Point",
22
+ coordinates: [values[2].to_f, values[1].to_f]},
23
+ properties: {placename: values[0],
24
+ html: render_leaflet_sidebar_partial(doc)}}
25
+ geojson_docs[:features].push feature
26
+ end
27
+ end
28
+ end
29
+ return geojson_docs.to_json
30
+ end
31
+
32
+ def render_leaflet_sidebar_partial(doc)
33
+ render partial: 'catalog/index_maps', locals: {document: SolrDocument.new(doc)}
34
+ end
35
+
36
+ end
@@ -0,0 +1,6 @@
1
+ <% # container for all documents in map view -%>
2
+ <div id="documents" class="map">
3
+ <%= show_map_div() %>
4
+ <div id="blacklight-map-sidebar"></div>
5
+ <%= javascript_tag "var geojson_docs = #{serialize_geojson}" %>
6
+ </div>
@@ -0,0 +1,9 @@
1
+ <% # the way each document will be viewed in the sidebar list -%>
2
+ <li class='media'>
3
+ <%= render_thumbnail_tag document, {class: 'sidebar-thumb media-object'}, {class: 'pull-left'} %>
4
+ <div class='media-body'>
5
+ <h4 class='media-heading'>
6
+ <%= link_to_document document, :label=>document_show_link_field(document) %>
7
+ </h4>
8
+ </div>
9
+ </li>