radiant-event_map-extension 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # Event Map Extension for Radiant
2
+
3
+ This extension adds mapping to the [event_calendar](http://github.com/radiant/radiant-event-calendar-extension). It will geocode your events automatically based on the address of the venue, or you can supply a postal code, UK postcode or grid reference for greater precision.
4
+
5
+ Events can be displayed on a google map and you can create links to bing or google maps that display the location of each event.
6
+
7
+ ## Installation
8
+
9
+ Should be straightforward:
10
+
11
+ script/extension install event_map
12
+
13
+ or as a gem:
14
+
15
+ gem install radiant-event_map-extension
16
+
17
+ ## Requirements
18
+
19
+ * [event_calendar](http://github.com/radiant/radiant-event-calendar-extension) extension
20
+ * [layouts](http://github.com/squaretalent/radiant-layouts-extension) or [share_layouts](http://github.com/radiant/radiant-share-layouts-extension) extension
21
+ * [geokit](http://geokit.rubyforge.org/) gem
22
+
23
+ ## Configuration
24
+
25
+ There is one required config setting:
26
+
27
+ * `event_map.layout` is the name of the layout used by the controller
28
+
29
+ ## Basic Usage
30
+
31
+ ### Linking to maps
32
+
33
+ We override the `url` method of EventVenue to return a map link if no other url is defined. The format of those links is determined by the link template stored in the config setting `event_map.link_format`. The markers :lat, :lng and :title will be replaced with the the correct value for each event venue.
34
+
35
+ There are also two shortcuts:
36
+
37
+ * 'google' is the default and equivalent to `http://maps.google.com/maps?q=:lat+:lng+(:title)` and will drop a pin on a google map.
38
+ * 'bing' is equivalent to `http://www.bing.com/maps/?v=2&cp=:lat~:lng&rtp=~pos.:lat_:lng_:title&lvl=15&sty=s&eo=0`, which will display a 1:25000 ordnance survey map (if you're in the UK) with a destination flag at your chosen point.
39
+
40
+ ### Displaying a map page
41
+
42
+ Create a layout that includes a `map_canvas` div and these page parts:
43
+
44
+ * `map_js` is required. It brings in the javascripts (and can be used in the header or at the end of the page as you prefer)
45
+ * `title` is the page title and can also be shown with `r:title`
46
+ * `faceting` here only gives the option to remove any date filters that have been applied. If you add the `taggable_events` extension it gets more useful.
47
+
48
+ Here's a starting point:
49
+
50
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
51
+ <head>
52
+ <title><r:title /></title>
53
+ <r:content part="map_js" />
54
+ </head>
55
+ <body>
56
+ <h1 id="pagetitle"><r:title /></h1>
57
+ <r:content part="faceting" />
58
+ <div id="map_canvas" style="width: 600px; height 400px;"></div>
59
+ </body>
60
+ </html>
61
+
62
+ Make sure that `Radiant::Config['event_map.layout']` matches exactly the _name_ of this layout.
63
+
64
+ ### javascript compatibility
65
+
66
+ The map javascript is generated by the EventVenuesController using `app/views/event_venues/index.js.erb`. It provides a `build_map_and_markers` method and the minimal jQuery hook required to populate #map_canvas when the DOM loads.
67
+
68
+ If you're not using jQuery you should find it straightforward to call `build_map_and_markers(div element)` from another script, and in that case you don't have to use our naming scheme either.
69
+
70
+ ### JSON interface
71
+
72
+ If you don't want to use the included scripts, you can skip that whole mechanism and work with the event data instead. EventVenuesController provides a simple JSON interface. Usually it's at /map and looks for addresses like this:
73
+
74
+ /map everything
75
+ /map/2010 events in 2010
76
+ /map/2010/12/ events in December 2010
77
+ /map/2010/12/12 events on 12 December 2010
78
+
79
+ If you're using `taggable_events` then we also inherit the tag-faceting interface here.
80
+
81
+ The data returned looks like this:
82
+
83
+ {
84
+
85
+ }
86
+
87
+ ## Bugs and features
88
+
89
+ [Github issues](http://github.com/spanner/radiant-event_map-extension/issues) please, or for little things an email or github message is fine.
90
+
91
+ ## Author & Copyright
92
+
93
+ Copyright 2008-2010 Will at spanner.org.
94
+
95
+ Released under the same terms as Radiant and/or Rails.
data/Rakefile ADDED
@@ -0,0 +1,138 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "radiant-event_map-extension"
5
+ gem.summary = %Q{Google mapping for events in the radiant CMS}
6
+ gem.description = %Q{Further extends the event_calendar extension to allow easy google mapping with automatic geolocation based on event venues}
7
+ gem.email = "will@spanner.org"
8
+ gem.homepage = "http://github.com/radiant/radiant-event_map-extension"
9
+ gem.authors = ["spanner"]
10
+ gem.add_dependency "geokit"
11
+ gem.add_dependency "radiant", ">= 0.9.0"
12
+ gem.add_dependency "radiant-event_calendar-extension"
13
+ end
14
+ rescue LoadError
15
+ puts "Jeweler (or a dependency) not available. This is only required if you plan to package event_map as a gem."
16
+ end
17
+
18
+ # In rails 1.2, plugins aren't available in the path until they're loaded.
19
+ # Check to see if the rspec plugin is installed first and require
20
+ # it if it is. If not, use the gem version.
21
+
22
+ # Determine where the RSpec plugin is by loading the boot
23
+ unless defined? RADIANT_ROOT
24
+ ENV["RAILS_ENV"] = "test"
25
+ case
26
+ when ENV["RADIANT_ENV_FILE"]
27
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
28
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
29
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
30
+ else
31
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
32
+ end
33
+ end
34
+
35
+ require 'rake'
36
+ require 'rake/rdoctask'
37
+ require 'rake/testtask'
38
+
39
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
40
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
41
+ require 'spec/rake/spectask'
42
+ require 'cucumber'
43
+ require 'cucumber/rake/task'
44
+
45
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
46
+ Object.send(:remove_const, :RADIANT_ROOT)
47
+
48
+ extension_root = File.expand_path(File.dirname(__FILE__))
49
+
50
+ task :default => :spec
51
+ task :stats => "spec:statsetup"
52
+
53
+ desc "Run all specs in spec directory"
54
+ Spec::Rake::SpecTask.new(:spec) do |t|
55
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
56
+ t.spec_files = FileList['spec/**/*_spec.rb']
57
+ end
58
+
59
+ task :features => 'spec:integration'
60
+
61
+ namespace :spec do
62
+ desc "Run all specs in spec directory with RCov"
63
+ Spec::Rake::SpecTask.new(:rcov) do |t|
64
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
65
+ t.spec_files = FileList['spec/**/*_spec.rb']
66
+ t.rcov = true
67
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
68
+ end
69
+
70
+ desc "Print Specdoc for all specs"
71
+ Spec::Rake::SpecTask.new(:doc) do |t|
72
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
73
+ t.spec_files = FileList['spec/**/*_spec.rb']
74
+ end
75
+
76
+ [:models, :controllers, :views, :helpers].each do |sub|
77
+ desc "Run the specs under spec/#{sub}"
78
+ Spec::Rake::SpecTask.new(sub) do |t|
79
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
80
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
81
+ end
82
+ end
83
+
84
+ desc "Run the Cucumber features"
85
+ Cucumber::Rake::Task.new(:integration) do |t|
86
+ t.fork = true
87
+ t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'pretty')]
88
+ # t.feature_pattern = "#{extension_root}/features/**/*.feature"
89
+ t.profile = "default"
90
+ end
91
+
92
+ # Setup specs for stats
93
+ task :statsetup do
94
+ require 'code_statistics'
95
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
96
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
97
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
98
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
99
+ ::CodeStatistics::TEST_TYPES << "Model specs"
100
+ ::CodeStatistics::TEST_TYPES << "View specs"
101
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
102
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
103
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
104
+ end
105
+
106
+ namespace :db do
107
+ namespace :fixtures do
108
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
109
+ task :load => :environment do
110
+ require 'active_record/fixtures'
111
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
112
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
113
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ desc 'Generate documentation for the event_map extension.'
121
+ Rake::RDocTask.new(:rdoc) do |rdoc|
122
+ rdoc.rdoc_dir = 'rdoc'
123
+ rdoc.title = 'EventMapExtension'
124
+ rdoc.options << '--line-numbers' << '--inline-source'
125
+ rdoc.rdoc_files.include('README')
126
+ rdoc.rdoc_files.include('lib/**/*.rb')
127
+ end
128
+
129
+ # For extensions that are in transition
130
+ desc 'Test the event_map extension.'
131
+ Rake::TestTask.new(:test) do |t|
132
+ t.libs << 'lib'
133
+ t.pattern = 'test/**/*_test.rb'
134
+ t.verbose = true
135
+ end
136
+
137
+ # Load any custom rakefiles for extension
138
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.1.0
@@ -0,0 +1,50 @@
1
+ # We inherit from EventsController to share subsetting functionality
2
+ # All we do here is organise that information by venue.
3
+
4
+ class EventVenuesController < EventsController
5
+ helper_method :venues, :events_at_venue
6
+ radiant_layout { |controller| controller.layout_for :event_map }
7
+
8
+ def index
9
+ respond_to do |format|
10
+ format.html { }
11
+ format.js {
12
+ render :layout => false
13
+ }
14
+ format.json {
15
+ render :json => venue_events.to_json
16
+ }
17
+ end
18
+ end
19
+
20
+ # event_finder is defined in EventsController
21
+
22
+ def events
23
+ @events ||= all_events
24
+ end
25
+
26
+ def venues
27
+ @venues ||= events.map(&:event_venue).compact.uniq
28
+ end
29
+
30
+ # events are stashed in venue buckets to avoid returning to the database
31
+
32
+ def events_at_venue(venue)
33
+ venue_events[venue.id]
34
+ end
35
+
36
+ protected
37
+
38
+ def venue_events
39
+ return @venue_events if @venue_events
40
+ @venue_events = {}
41
+ events.each do |e|
42
+ if e.event_venue
43
+ @venue_events[e.event_venue.id] ||= []
44
+ @venue_events[e.event_venue.id].push(e)
45
+ end
46
+ end
47
+ @venue_events
48
+ end
49
+
50
+ end
@@ -0,0 +1,20 @@
1
+ - without_title ||= false
2
+
3
+ - if event
4
+ .map_event
5
+ - unless without_title
6
+ %h3.event
7
+ = link_to event.title, event.url
8
+
9
+ %p.date
10
+ %strong
11
+ = event.summarize_period
12
+ - if event.event_venue
13
+ at
14
+ = link_to event.event_venue.title, event.event_venue.url
15
+ - else
16
+ at
17
+ = event.location
18
+
19
+ %p.description
20
+ = event.short_description
@@ -0,0 +1,23 @@
1
+ - if venue
2
+ - if events = events_at_venue(venue)
3
+ .map_venue
4
+ - if events.length == 1
5
+ = render :partial => 'event', :object => events.first
6
+ - else
7
+ %h3
8
+ Events at
9
+ = link_to venue.title, venue.url
10
+ %ul
11
+ - remainder = events.slice!(4, 10000)
12
+ - events.each do |event|
13
+ %li
14
+ %strong
15
+ = link_to event.title, event.url
16
+ on
17
+ = event.date
18
+ - if remainder && remainder.any?
19
+ %li
20
+ and
21
+ = remainder.length
22
+ more events...
23
+
@@ -0,0 +1,17 @@
1
+ - content_for :title do
2
+ Events
3
+ = list_description
4
+
5
+ - content_for :faceting do
6
+ = render :partial => 'events/faceting'
7
+
8
+ - content_for :map_js do
9
+ %script{:src => "http://maps.google.com/maps/api/js?sensor=false"}
10
+ %script{:src => "#{url_for(calendar_parameters.merge(:format => :js))}"}
11
+
12
+ / deprecated older syntax probably unknown to anyone but me
13
+ - content_for :head do
14
+ %script{:src => "http://maps.google.com/maps/api/js?sensor=false"}
15
+ %script{:src => "#{url_for(calendar_parameters.merge(:format => :js))}"}
16
+
17
+ = render :partial => 'events/other_page_parts'
@@ -0,0 +1,55 @@
1
+ if(typeof jQuery == 'function') {
2
+ jQuery.fn.populate_map = function() {
3
+ this.each(function() { build_map_and_markers(this); });
4
+ };
5
+
6
+ jQuery(function() {
7
+ jQuery("#map_canvas").populate_map();
8
+ });
9
+ }
10
+
11
+ function build_map_and_markers(element) {
12
+ if (element != null) {
13
+ var map = new google.maps.Map(element, {mapTypeId: google.maps.MapTypeId.ROADMAP});
14
+ var bounds = new google.maps.LatLngBounds();
15
+ var one_icon = new google.maps.MarkerImage('/images/event_calendar/one_event.png',
16
+ new google.maps.Size(26,45),
17
+ new google.maps.Point(0,0),
18
+ new google.maps.Point(7, 45));
19
+ var several_icon = new google.maps.MarkerImage('/images/event_calendar/several_events.png',
20
+ new google.maps.Size(26,45),
21
+ new google.maps.Point(0,0),
22
+ new google.maps.Point(9, 45));
23
+ var one_shadow = new google.maps.MarkerImage('/images/event_calendar/event_shadow.png',
24
+ new google.maps.Size(60, 44),
25
+ new google.maps.Point(0,0),
26
+ new google.maps.Point(8, 45));
27
+ var several_shadow = new google.maps.MarkerImage('/images/event_calendar/event_shadow.png',
28
+ new google.maps.Size(60, 44),
29
+ new google.maps.Point(0,0),
30
+ new google.maps.Point(5, 45));
31
+ <% venues.each do |venue| %>
32
+ add_marker(map, {
33
+ title : "<%= escape_javascript(venue.title) %>",
34
+ image : <%= events_at_venue(venue).length > 1 ? "several_icon" : "one_icon" %>,
35
+ shadow : <%= events_at_venue(venue).length > 1 ? "several_shadow" : "one_shadow" %>,
36
+ position : new google.maps.LatLng("<%= venue.lat %>","<%= venue.lng %>"),
37
+ description : "<%= escape_javascript(render :partial => 'venue', :object => venue) %>"
38
+ });
39
+ bounds.extend(new google.maps.LatLng("<%= venue.lat %>","<%= venue.lng %>"));
40
+ <% end %>
41
+ map.fitBounds(bounds);
42
+ }
43
+ }
44
+
45
+ function add_marker (map, mark) {
46
+ var marker = new google.maps.Marker({ map : map, position : mark['position'], title : mark['title'], icon : mark['image'], shadow : mark['shadow'] });
47
+ var infowindow = new google.maps.InfoWindow({ content : mark['description'] , maxWidth : 400 });
48
+ google.maps.event.addListener(marker, 'click', function() { infowindow.open(map, marker); });
49
+ }
50
+
51
+
52
+
53
+
54
+
55
+
@@ -0,0 +1,11 @@
1
+ %span.calendar_views
2
+ %br
3
+ View as
4
+ = link_to("map", eventmap_url(calendar_parameters))
5
+ or
6
+ = link_to("calendar", calendar_url(calendar_parameters)) + "."
7
+ Stay up to date with
8
+ = link_to("RSS", calendar_url(calendar_parameters.merge(:format => :rss)))
9
+ or
10
+ = link_to("calendar feed", calendar_url(calendar_parameters.merge(:format => :ics, :protocol => 'webcal://', :only_path => false)))
11
+
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.with_options :controller => 'event_venues', :action => 'index' do |m|
3
+ m.eventmap "/map.:format"
4
+ m.eventmap_year "/map/:year.:format"
5
+ m.eventmap_month "/map/:year/:month.:format"
6
+ m.eventmap_day "/map/:year/:month/:mday.:format"
7
+ end
8
+ end
data/cucumber.yml ADDED
@@ -0,0 +1 @@
1
+ default: --format progress features --tags ~@proposed,~@in_progress
@@ -0,0 +1,20 @@
1
+ class LatLong < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :events, :lat, :string
4
+ add_column :events, :lng, :string
5
+ add_column :event_venues, :lat, :string
6
+ add_column :event_venues, :lng, :string
7
+ add_index :events, [:lat, :lng]
8
+ add_index :event_venues, [:lat, :lng]
9
+
10
+ end
11
+
12
+ def self.down
13
+ remove_column :events, :lat
14
+ remove_column :events, :lng
15
+ remove_column :event_venues, :lat
16
+ remove_column :event_venues, :lng
17
+ remove_index :events, [:lat, :lng]
18
+ remove_index :event_venues, [:lat, :lng]
19
+ end
20
+ end