refinerycms-map 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ class Admin::MapLocationsController < Admin::BaseController
2
+
3
+ crudify :map_location, :order => "state, city"
4
+
5
+ end
@@ -0,0 +1,25 @@
1
+ class MapLocationsController < ApplicationController
2
+
3
+ before_filter :find_locations, :find_page
4
+ before_filter :find_location, :only => [:show]
5
+
6
+ protected
7
+
8
+ def find_locations
9
+ if params[:q]
10
+ coords = Geocode.find_address(params[:q])
11
+ @map_locations = MapLocation.nearest_to(coords.latitude, coords.longitude, 50)
12
+ else
13
+ @map_locations = MapLocation.all
14
+ end
15
+ end
16
+
17
+ def find_location
18
+ @map_location = MapLocation.find(params[:id])
19
+ end
20
+
21
+ def find_page
22
+ @page = Page.find_by_link_url("/map")
23
+ end
24
+
25
+ end
@@ -0,0 +1,59 @@
1
+ class MapLocation < ActiveRecord::Base
2
+
3
+ validates_presence_of :title, :address, :city, :state, :zipcode
4
+
5
+ has_friendly_id :title, :use_slug => true
6
+
7
+ acts_as_indexed :fields => [:title, :address, :city, :state, :zipcode]
8
+
9
+ default_scope :order => "state, city, title"
10
+
11
+ before_save :set_lat_and_lng
12
+
13
+ # for will_paginate
14
+ def self.per_page
15
+ 20
16
+ end
17
+
18
+ ##
19
+ # Returns a scope which queries for the nearest locations to the requested
20
+ # coordinates (latitude and longitude in decimal format).
21
+ #
22
+ # This method uses a variation of the Haversine Formula. Conversions have
23
+ # already been made to radians and the Earth's radius (3956mi) has already
24
+ # been baked in. The variation arises where the distance is not calculated
25
+ # against every instance in the database, instead a rough box is drawn
26
+ # around the source point that encapsulates the desired radius. Only those
27
+ # objects within the box are calculated for distance.
28
+ #
29
+ def self.nearest_to(latitude, longitude, radius = 100)
30
+ latitude_delta = radius.to_f / 69.0
31
+ longitude_delta = radius.to_f / (Math.cos(latitude) * 69.0).abs
32
+ scoped({
33
+ :select => "*, 7912 * ASIN(SQRT(POWER(SIN((#{latitude} - lat) * 0.00872664626), 2) + COS(#{latitude} * 0.0174532925) * COS(#{latitude} * 0.0174532925) * POWER(SIN((#{longitude} - lng) * 0.00872664626), 2))) as distance_from_source",
34
+ :order => 'distance_from_source ASC',
35
+ :conditions => "lat BETWEEN #{latitude - latitude_delta} AND #{latitude + latitude_delta} AND lng BETWEEN #{longitude - longitude_delta} AND #{longitude + longitude_delta}"
36
+ })
37
+ end
38
+
39
+ def full_address
40
+ "%s, %s, %s %s" % [self.address, self.city, self.state, self.zipcode]
41
+ end
42
+
43
+
44
+ private
45
+
46
+
47
+ def set_lat_and_lng
48
+ if address_changed? || city_changed? || state_changed? || zipcode_changed?
49
+ Geocode.find_address(self.full_address).tap do |coordinate|
50
+ self.lat = coordinate.latitude
51
+ self.lng = coordinate.longitude
52
+ end
53
+ end
54
+ end
55
+
56
+ def lat=(input); write_attribute(:lat, input); end
57
+ def lng=(input); write_attribute(:lng, input); end
58
+
59
+ end
@@ -0,0 +1,54 @@
1
+ <% form_for [:admin, @map_location] do |f| %>
2
+ <%= f.error_messages %>
3
+
4
+ <div class='hemisquare'>
5
+ <div class='field'>
6
+ <%= f.label :title %>
7
+ <%= f.text_field :title, :class => "larger widest" %>
8
+ </div>
9
+
10
+ <div class='field'>
11
+ <%= f.label :address %>
12
+ <%= f.text_field :address %>
13
+ </div>
14
+
15
+ <div class='field'>
16
+ <%= f.label :city %>
17
+ <%= f.text_field :city %>
18
+ </div>
19
+
20
+ <div class='field'>
21
+ <%= f.label :state %>
22
+ <%= f.text_field :state %>
23
+ </div>
24
+
25
+ <div class='field'>
26
+ <%= f.label :zipcode %>
27
+ <%= f.text_field :zipcode %>
28
+ </div>
29
+
30
+ <div class='field'>
31
+ <%= f.label :phone %>
32
+ <%= f.text_field :phone %>
33
+ </div>
34
+
35
+ <div class='field'>
36
+ <%= f.label :url %>
37
+ <%= f.text_field :url %>
38
+ </div>
39
+ </div>
40
+
41
+ <div class='hemisquare right_side'>
42
+ <br/><br/><br/><br/><br/><br/><br/>
43
+ <%= image_tag "http://maps.google.com/maps/api/staticmap?size=400x400&markers=#{@map_location.full_address.parameterize('+')}&zoom=14&sensor=false", :class => "location_map" %>
44
+ </div>
45
+
46
+ <div class='clearfix'></div>
47
+
48
+ <%= render :partial => "/shared/admin/form_actions",
49
+ :locals => {
50
+ :f => f,
51
+ :continue_editing => false
52
+ } %>
53
+
54
+ <% end %>
@@ -0,0 +1,16 @@
1
+ <li class='clearfix record <%= cycle("on", "on-hover") %>'>
2
+ <span class='title'>
3
+ <%=h map_location.title %>
4
+ <span class="preview"><%=h map_location.full_address %></span>
5
+ </span>
6
+ <span class='actions'>
7
+ <%= link_to refinery_icon_tag('application_go.png'), map_location_url(map_location),
8
+ :title => t('.view_live'),
9
+ :target => "_blank" %>
10
+ <%= link_to refinery_icon_tag('application_edit.png'), edit_admin_map_location_path(map_location),
11
+ :title => t('.edit') %>
12
+ <%= link_to refinery_icon_tag('delete.png'), admin_map_location_path(map_location),
13
+ :class => "cancel confirm-delete",
14
+ :title => t('.delete') %>
15
+ </span>
16
+ </li>
@@ -0,0 +1 @@
1
+ <%= render :partial => "form" %>
@@ -0,0 +1,28 @@
1
+ <div id='actions'>
2
+ <ul>
3
+ <li>
4
+ <%= render :partial => "/shared/admin/search", :locals => {:url => admin_map_locations_url} %>
5
+ </li>
6
+ <li>
7
+ <%= link_to t('.create'), new_admin_map_location_url, :class => "add_icon" %>
8
+ </li>
9
+ </ul>
10
+ </div>
11
+ <div id='records'>
12
+ <%= "<h2>#{t('admin.search_results_for', :query => params[:search])}</h2>" if searching? %>
13
+ <% if @map_locations.any? %>
14
+ <%= will_paginate @map_locations, :previous_label => '&laquo;', :next_label => '&raquo;' %>
15
+ <ul>
16
+ <%= render :partial => "map_location", :collection => @map_locations %>
17
+ </ul>
18
+ <%= will_paginate @map_locations, :previous_label => '&laquo;', :next_label => '&raquo;' %>
19
+ <% else %>
20
+ <% unless searching? %>
21
+ <p>
22
+ <strong><%= t('.no_items_yet') %></strong>
23
+ </p>
24
+ <% else %>
25
+ <p><%= t('admin.search_no_results') %></p>
26
+ <% end %>
27
+ <% end %>
28
+ </div>
@@ -0,0 +1 @@
1
+ <%= render :partial => "form" %>
@@ -0,0 +1,10 @@
1
+ <% content_for :body_content_left do %>
2
+ <%= @page[:body] if @map_locations.empty? %>
3
+ <%= render :partial => 'map', :locals => {:width => 500, :height => 500} %>
4
+ <% end %>
5
+
6
+ <% content_for :body_content_right do %>
7
+ <%= render :partial => 'locations' %>
8
+ <% end %>
9
+
10
+ <%= render :partial => "/shared/content_page" %>
@@ -0,0 +1,9 @@
1
+ <% content_for :body_content_title, "<h1>#{@map_location.title}</h1>" %>
2
+ <% content_for :body_content_left do %>
3
+ <h2>Map Goes Here</h2>
4
+ <% end %>
5
+ <% content_for :body_content_right do %>
6
+ <h3>Location Details Go Here</h3>
7
+ <% end %>
8
+
9
+ <%= render :partial => "/shared/content_page" %>
@@ -0,0 +1,31 @@
1
+ en:
2
+ plugins:
3
+ map:
4
+ title: Map
5
+ admin:
6
+ map_locations:
7
+ map_location:
8
+ view_live: "View this location live on the map<br/><em>(opens in a new window)</em>"
9
+ edit: "Edit this location"
10
+ delete: "Remove this location forever"
11
+ index:
12
+ actions: Actions
13
+ create: "Create Location"
14
+ news_item: Location
15
+ no_items: "Sorry, no results found."
16
+ no_items_yet: 'There are no locations yet. Click "Create Location" to add one.'
17
+ map_locations:
18
+ show:
19
+ back_to_index: "Back to the map"
20
+ activerecord:
21
+ attributes:
22
+ map_location:
23
+ title: Title
24
+ address: Address
25
+ city: City
26
+ state: State
27
+ zipcode: Zip Code
28
+ phone: Phone Number
29
+ url: Url
30
+ models:
31
+ map_location: Location
data/config/routes.rb ADDED
@@ -0,0 +1,7 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.resources :map_locations, :as => :map
3
+
4
+ map.namespace(:admin, :path_prefix => (defined?(REFINERY_GEM_VERSION) ? 'admin' : 'refinery')) do |admin|
5
+ admin.resources :map_locations, :as => :map
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ class MapGenerator < Rails::Generator::NamedBase
2
+
3
+ def initialize(*runtime_args)
4
+ # set first argument to the table's name so that the user doesn't have to pass it in.
5
+ runtime_args[0] = ["map_locations"]
6
+ super(*runtime_args)
7
+ end
8
+
9
+ def banner
10
+ "Usage: script/generate map"
11
+ end
12
+
13
+ def manifest
14
+ record do |m|
15
+ m.migration_template 'migration.rb', 'db/migrate',
16
+ :migration_file_name => "create_structure_for_map",
17
+ :assigns => {
18
+ :migration_name => "CreateStructureForMap",
19
+ :table_name => "map_locations",
20
+ :attributes => [
21
+ Rails::Generator::GeneratedAttribute.new("title", "string"),
22
+ Rails::Generator::GeneratedAttribute.new("address", "string"),
23
+ Rails::Generator::GeneratedAttribute.new("city", "string"),
24
+ Rails::Generator::GeneratedAttribute.new("state", "string"),
25
+ Rails::Generator::GeneratedAttribute.new("zipcode", "string"),
26
+ Rails::Generator::GeneratedAttribute.new("phone", "string"),
27
+ Rails::Generator::GeneratedAttribute.new("url", "string"),
28
+ ]
29
+ }
30
+ m.file "jquery.jmapping.min.js", "public/javascripts/jquery.jmapping.min.js"
31
+ m.file "jquery.metadata.js", "public/javascripts/jquery.metadata.js"
32
+ m.file "mapiconmaker.js", "public/javascripts/mapiconmaker.js"
33
+ m.file "markermanager.js", "public/javascripts/markermanager.js"
34
+ end
35
+ end
36
+
37
+ end if defined?(Rails::Generator::NamedBase)
@@ -0,0 +1,20 @@
1
+ /*
2
+ * jMapping v1.4.0 - jQuery plugin for creating Google Maps
3
+ *
4
+ * Copyright (c) 2009-2010 Brian Landau (Viget Labs)
5
+ * MIT License: http://www.opensource.org/licenses/mit-license.php
6
+ *
7
+ */
8
+ if(GMap2){GMap2.prototype.centerAndZoomOnBounds=function(bounds){this.setCenter(bounds.getCenter(),this.getBoundsZoomLevel(bounds));};}
9
+ (function($){$.jMapping=function(map_elm,options){var settings,gmarkers,mapped,map,markerManager,places,bounds,jMapper;map_elm=(typeof map_elm=="string")?$(map_elm).get(0):map_elm;if(!($(map_elm).data('jMapping'))){settings=$.extend(true,{},$.jMapping.defaults);$.extend(true,settings,options);gmarkers={};var init=function(doUpdate){var info_window_selector,min_zoom,bounds_zoom_level;info_window_selector=[settings.side_bar_selector,settings.location_selector,settings.info_window_selector].join(' ');$(info_window_selector).hide();places=getPlaces();bounds=getBounds(doUpdate);if(doUpdate){gmarkers={};markerManager.clearMarkers();map.checkResize();map.centerAndZoomOnBounds(bounds);}else{map=createMap();markerManager=new MarkerManager(map);}
10
+ places.each(function(){var marker=createMarker(this);if(!(settings.link_selector===false)){setupLink(this);}
11
+ $(document).trigger('markerCreated.jMapping',[marker]);});bounds_zoom_level=map.getBoundsZoomLevel(bounds);min_zoom=(bounds_zoom_level<7)?0:(bounds_zoom_level-7);markerManager.addMarkers(gmarkersArray(),min_zoom);markerManager.refresh();if(!(settings.link_selector===false)&&!doUpdate){attachMapsEventToLinks();}};var createMap=function(){map=new GMap2(map_elm);if($.isFunction(settings.map_config)){settings.map_config(map);}else{map.setMapType(G_NORMAL_MAP);map.addControl(new GSmallMapControl());}
12
+ map.centerAndZoomOnBounds(bounds);if(typeof settings.default_zoom_level=="number"){map.setZoom(settings.default_zoom_level);}
13
+ return map;};var getPlaces=function(){return $(settings.side_bar_selector+' '+settings.location_selector);};var getPlacesData=function(doUpdate){return places.map(function(){if(doUpdate){$(this).data('metadata',false);}
14
+ return $(this).metadata(settings.metadata_options);});};var getBounds=function(doUpdate){var places_data=getPlacesData(doUpdate);var newBounds=new GLatLngBounds($.jMapping.makeGLatLng(places_data[0].point),$.jMapping.makeGLatLng(places_data[0].point));for(var i=1,len=places_data.length;i<len;i++){newBounds.extend($.jMapping.makeGLatLng(places_data[i].point));}
15
+ return newBounds;};var setupLink=function(place_elm){var $place_elm=$(place_elm),location_data=$place_elm.metadata(settings.metadata_options),link=$place_elm.find(settings.link_selector);link.attr('href',("#"+location_data.id));};var chooseIconOptions=function(category){if(settings.category_icon_options){if($.isFunction(settings.category_icon_options)){return settings.category_icon_options(category);}else{return settings.category_icon_options[category]||settings.category_icon_options['default'];}}else{return{};}};var createMarker=function(place_elm){var $place_elm=$(place_elm),place_data,point,marker,$info_window_elm,custom_icon,icon_options;place_data=$place_elm.metadata(settings.metadata_options);point=$.jMapping.makeGLatLng(place_data.point);if(settings.category_icon_options){icon_options=chooseIconOptions(place_data.category);if(typeof icon_options==="string"){custom_icon=new GIcon(G_DEFAULT_ICON,icon_options);}else if(icon_options instanceof GIcon){custom_icon=icon_options;}else{if(!icon_options.style)icon_options.style='Marker';custom_icon=MapIconMaker['create'+icon_options.style+'Icon'](icon_options);}
16
+ marker=new GMarker(point,{icon:custom_icon});}else{marker=new GMarker(point);}
17
+ $info_window_elm=$place_elm.find(settings.info_window_selector);if($info_window_elm.length>0){marker.bindInfoWindowHtml($info_window_elm.html(),{maxWidth:settings.info_window_max_width});}
18
+ gmarkers[parseInt(place_data.id,10)]=marker;return marker;};var attachMapsEventToLinks=function(){var location_link_selector=[settings.side_bar_selector,settings.location_selector,settings.link_selector].join(' ');$(location_link_selector).live('click',function(e){e.preventDefault();var marker_index=parseInt($(this).attr('href').split('#')[1],10);GEvent.trigger(gmarkers[marker_index],"click");});};var gmarkersArray=function(){var marker_arr=[];$.each(gmarkers,function(key,value){marker_arr.push(value);});return marker_arr;};if(GBrowserIsCompatible()){if($(document).trigger('beforeMapping.jMapping',[settings])!=false){init();mapped=true;}else{mapped=false;}
19
+ jMapper={gmarkers:gmarkers,settings:settings,mapped:mapped,map:map,markerManager:markerManager,gmarkersArray:gmarkersArray,getBounds:getBounds,getPlacesData:getPlacesData,getPlaces:getPlaces,update:function(){if($(document).trigger('beforeUpdate.jMapping',[this])!=false){init(true);this.map=map;this.gmarkers=gmarkers;this.markerManager=markerManager;$(document).trigger('afterUpdate.jMapping',[this]);}}};$(document).trigger('afterMapping.jMapping',[jMapper]);return jMapper;}else{mapped=false;return null;}}else{return $(map_elm).data('jMapping');}};$.extend($.jMapping,{defaults:{side_bar_selector:'#map-side-bar:first',location_selector:'.map-location',link_selector:'a.map-link',info_window_selector:'.info-box',info_window_max_width:425,metadata_options:{type:'attr',name:'data-jmapping'}},makeGLatLng:function(place_point){return new GLatLng(place_point.lat,place_point.lng);}});$.fn.jMapping=function(options){if((options=='update')&&$(this[0]).data('jMapping')){$(this[0]).data('jMapping').update();}else{if(options=='update')options={};$(this[0]).data('jMapping',$.jMapping(this[0],options));}
20
+ return this;};})(jQuery);
@@ -0,0 +1,148 @@
1
+ /*
2
+ * Metadata - jQuery plugin for parsing metadata from elements
3
+ *
4
+ * Copyright (c) 2006 John Resig, Yehuda Katz, J�örn Zaefferer, Paul McLanahan
5
+ *
6
+ * Dual licensed under the MIT and GPL licenses:
7
+ * http://www.opensource.org/licenses/mit-license.php
8
+ * http://www.gnu.org/licenses/gpl.html
9
+ *
10
+ * Revision: $Id: jquery.metadata.js 3640 2007-10-11 18:34:38Z pmclanahan $
11
+ *
12
+ */
13
+
14
+ /**
15
+ * Sets the type of metadata to use. Metadata is encoded in JSON, and each property
16
+ * in the JSON will become a property of the element itself.
17
+ *
18
+ * There are four supported types of metadata storage:
19
+ *
20
+ * attr: Inside an attribute. The name parameter indicates *which* attribute.
21
+ *
22
+ * class: Inside the class attribute, wrapped in curly braces: { }
23
+ *
24
+ * elem: Inside a child element (e.g. a script tag). The
25
+ * name parameter indicates *which* element.
26
+ * html5: Values are stored in data-* attributes.
27
+ *
28
+ * The metadata for an element is loaded the first time the element is accessed via jQuery.
29
+ *
30
+ * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
31
+ * matched by expr, then redefine the metadata type and run another $(expr) for other elements.
32
+ *
33
+ * @name $.metadata.setType
34
+ *
35
+ * @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
36
+ * @before $.metadata.setType("class")
37
+ * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
38
+ * @desc Reads metadata from the class attribute
39
+ *
40
+ * @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
41
+ * @before $.metadata.setType("attr", "data")
42
+ * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
43
+ * @desc Reads metadata from a "data" attribute
44
+ *
45
+ * @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
46
+ * @before $.metadata.setType("elem", "script")
47
+ * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
48
+ * @desc Reads metadata from a nested script element
49
+ *
50
+ * @example <p id="one" class="some_class" data-item_id="1" data-item_label="Label">This is a p</p>
51
+ * @before $.metadata.setType("html5")
52
+ * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
53
+ * @desc Reads metadata from a series of data-* attributes
54
+ *
55
+ * @param String type The encoding type
56
+ * @param String name The name of the attribute to be used to get metadata (optional)
57
+ * @cat Plugins/Metadata
58
+ * @descr Sets the type of encoding to be used when loading metadata for the first time
59
+ * @type undefined
60
+ * @see metadata()
61
+ */
62
+
63
+ (function($) {
64
+
65
+ $.extend({
66
+ metadata : {
67
+ defaults : {
68
+ type: 'class',
69
+ name: 'metadata',
70
+ cre: /({.*})/,
71
+ single: 'metadata'
72
+ },
73
+ setType: function( type, name ){
74
+ this.defaults.type = type;
75
+ this.defaults.name = name;
76
+ },
77
+ get: function( elem, opts ){
78
+ var settings = $.extend({},this.defaults,opts);
79
+ // check for empty string in single property
80
+ if ( !settings.single.length ) settings.single = 'metadata';
81
+
82
+ var data = $.data(elem, settings.single);
83
+ // returned cached data if it already exists
84
+ if ( data ) return data;
85
+
86
+ data = "{}";
87
+
88
+ var getData = function(data) {
89
+ if(typeof data != "string") return data;
90
+
91
+ if( data.indexOf('{') < 0 ) {
92
+ data = eval("(" + data + ")");
93
+ }
94
+ }
95
+
96
+ var getObject = function(data) {
97
+ if(typeof data != "string") return data;
98
+
99
+ data = eval("(" + data + ")");
100
+ return data;
101
+ }
102
+
103
+ if ( settings.type == "html5" ) {
104
+ var object = {};
105
+ $( elem.attributes ).each(function() {
106
+ var name = this.nodeName;
107
+ if(name.match(/^data-/)) name = name.replace(/^data-/, '');
108
+ else return true;
109
+ object[name] = getObject(this.nodeValue);
110
+ });
111
+ } else {
112
+ if ( settings.type == "class" ) {
113
+ var m = settings.cre.exec( elem.className );
114
+ if ( m )
115
+ data = m[1];
116
+ } else if ( settings.type == "elem" ) {
117
+ if( !elem.getElementsByTagName ) return;
118
+ var e = elem.getElementsByTagName(settings.name);
119
+ if ( e.length )
120
+ data = $.trim(e[0].innerHTML);
121
+ } else if ( elem.getAttribute != undefined ) {
122
+ var attr = elem.getAttribute( settings.name );
123
+ if ( attr )
124
+ data = attr;
125
+ }
126
+ object = getObject(data.indexOf("{") < 0 ? "{" + data + "}" : data);
127
+ }
128
+
129
+ $.data( elem, settings.single, object );
130
+ return object;
131
+ }
132
+ }
133
+ });
134
+
135
+ /**
136
+ * Returns the metadata object for the first member of the jQuery object.
137
+ *
138
+ * @name metadata
139
+ * @descr Returns element's metadata object
140
+ * @param Object opts An object contianing settings to override the defaults
141
+ * @type jQuery
142
+ * @cat Plugins/Metadata
143
+ */
144
+ $.fn.metadata = function( opts ){
145
+ return $.metadata.get( this[0], opts );
146
+ };
147
+
148
+ })(jQuery);
@@ -0,0 +1,227 @@
1
+ /**
2
+ * @name MapIconMaker
3
+ * @version 1.1
4
+ * @author Pamela Fox
5
+ * @copyright (c) 2008 Pamela Fox
6
+ * @homepage http://gmaps-utility-library.googlecode.com/svn/trunk/mapiconmaker
7
+ * @fileoverview This gives you static functions for creating dynamically
8
+ * sized and colored marker icons using the Charts API marker output.
9
+ */
10
+
11
+ /*
12
+ * Licensed under the Apache License, Version 2.0 (the "License");
13
+ * you may not use this file except in compliance with the License.
14
+ * You may obtain a copy of the License at
15
+ *
16
+ * http://www.apache.org/licenses/LICENSE-2.0
17
+ *
18
+ * Unless required by applicable law or agreed to in writing, software
19
+ * distributed under the License is distributed on an "AS IS" BASIS,
20
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ * See the License for the specific language governing permissions and
22
+ * limitations under the License.
23
+ */
24
+
25
+ /**
26
+ * @name MarkerIconOptions
27
+ * @class This class represents optional arguments to {@link createMarkerIcon},
28
+ * {@link createFlatIcon}, or {@link createLabeledMarkerIcon}. Each of the
29
+ * functions use a subset of these arguments. See the function descriptions
30
+ * for the list of supported options.
31
+ * @property {Number} [width=32] Specifies, in pixels, the width of the icon.
32
+ * The width may include some blank space on the side, depending on the
33
+ * height of the icon, as the icon will scale its shape proportionately.
34
+ * @property {Number} [height=32] Specifies, in pixels, the height of the icon.
35
+ * @property {String} [primaryColor="#ff0000"] Specifies, as a hexadecimal
36
+ * string, the color used for the majority of the icon body.
37
+ * @property {String} [cornerColor="#ffffff"] Specifies, as a hexadecimal
38
+ * string, the color used for the top corner of the icon. If you'd like the
39
+ * icon to have a consistent color, make the this the same as the
40
+ * {@link primaryColor}.
41
+ * @property {String} [strokeColor="#000000"] Specifies, as a hexadecimal
42
+ * string, the color used for the outside line (stroke) of the icon.
43
+ * @property {String} [shadowColor="#000000"] Specifies, as a hexadecimal
44
+ * string, the color used for the shadow of the icon.
45
+ * @property {String} [label=""] Specifies a character or string to display
46
+ * inside the body of the icon. Generally, one or two characters looks best.
47
+ * @property {String} [labelColor="#000000"] Specifies, as a hexadecimal
48
+ * string, the color used for the label text.
49
+ * @property {Number} [labelSize=0] Specifies, in pixels, the size of the label
50
+ * text. If set to 0, the text auto-sizes to fit the icon body.
51
+ * @property {String} [shape="circle"] Specifies shape of the icon. Current
52
+ * options are "circle" for a circle or "roundrect" for a rounded rectangle.
53
+ * @property {Boolean} [addStar = false] Specifies whether to add a star to the
54
+ * edge of the icon.
55
+ * @property {String} [starPrimaryColor="#FFFF00"] Specifies, as a hexadecimal
56
+ * string, the color used for the star body.
57
+ * @property {String} [starStrokeColor="#0000FF"] Specifies, as a hexadecimal
58
+ * string, the color used for the outside line (stroke) of the star.
59
+ */
60
+
61
+ /**
62
+ * This namespace contains functions that you can use to easily create
63
+ * dynamically sized, colored, and labeled icons.
64
+ * @namespace
65
+ */
66
+ var MapIconMaker = {};
67
+
68
+ /**
69
+ * Creates an icon based on the specified options in the
70
+ * {@link MarkerIconOptions} argument.
71
+ * Supported options are: width, height, primaryColor,
72
+ * strokeColor, and cornerColor.
73
+ * @param {MarkerIconOptions} [opts]
74
+ * @return {GIcon}
75
+ */
76
+ MapIconMaker.createMarkerIcon = function (opts) {
77
+ var width = opts.width || 32;
78
+ var height = opts.height || 32;
79
+ var primaryColor = opts.primaryColor || "#ff0000";
80
+ var strokeColor = opts.strokeColor || "#000000";
81
+ var cornerColor = opts.cornerColor || "#ffffff";
82
+
83
+ var baseUrl = "http://chart.apis.google.com/chart?cht=mm";
84
+ var iconUrl = baseUrl + "&chs=" + width + "x" + height +
85
+ "&chco=" + cornerColor.replace("#", "") + "," +
86
+ primaryColor.replace("#", "") + "," +
87
+ strokeColor.replace("#", "") + "&ext=.png";
88
+ var icon = new GIcon(G_DEFAULT_ICON);
89
+ icon.image = iconUrl;
90
+ icon.iconSize = new GSize(width, height);
91
+ icon.shadowSize = new GSize(Math.floor(width * 1.6), height);
92
+ icon.iconAnchor = new GPoint(width / 2, height);
93
+ icon.infoWindowAnchor = new GPoint(width / 2, Math.floor(height / 12));
94
+ icon.printImage = iconUrl + "&chof=gif";
95
+ icon.mozPrintImage = iconUrl + "&chf=bg,s,ECECD8" + "&chof=gif";
96
+ iconUrl = baseUrl + "&chs=" + width + "x" + height +
97
+ "&chco=" + cornerColor.replace("#", "") + "," +
98
+ primaryColor.replace("#", "") + "," +
99
+ strokeColor.replace("#", "");
100
+ icon.transparent = iconUrl + "&chf=a,s,ffffff11&ext=.png";
101
+
102
+ icon.imageMap = [
103
+ width / 2, height,
104
+ (7 / 16) * width, (5 / 8) * height,
105
+ (5 / 16) * width, (7 / 16) * height,
106
+ (7 / 32) * width, (5 / 16) * height,
107
+ (5 / 16) * width, (1 / 8) * height,
108
+ (1 / 2) * width, 0,
109
+ (11 / 16) * width, (1 / 8) * height,
110
+ (25 / 32) * width, (5 / 16) * height,
111
+ (11 / 16) * width, (7 / 16) * height,
112
+ (9 / 16) * width, (5 / 8) * height
113
+ ];
114
+ for (var i = 0; i < icon.imageMap.length; i++) {
115
+ icon.imageMap[i] = parseInt(icon.imageMap[i]);
116
+ }
117
+
118
+ return icon;
119
+ };
120
+
121
+
122
+ /**
123
+ * Creates a flat icon based on the specified options in the
124
+ * {@link MarkerIconOptions} argument.
125
+ * Supported options are: width, height, primaryColor,
126
+ * shadowColor, label, labelColor, labelSize, and shape..
127
+ * @param {MarkerIconOptions} [opts]
128
+ * @return {GIcon}
129
+ */
130
+ MapIconMaker.createFlatIcon = function (opts) {
131
+ var width = opts.width || 32;
132
+ var height = opts.height || 32;
133
+ var primaryColor = opts.primaryColor || "#ff0000";
134
+ var shadowColor = opts.shadowColor || "#000000";
135
+ var label = MapIconMaker.escapeUserText_(opts.label) || "";
136
+ var labelColor = opts.labelColor || "#000000";
137
+ var labelSize = opts.labelSize || 0;
138
+ var shape = opts.shape || "circle";
139
+ var shapeCode = (shape === "circle") ? "it" : "itr";
140
+
141
+ var baseUrl = "http://chart.apis.google.com/chart?cht=" + shapeCode;
142
+ var iconUrl = baseUrl + "&chs=" + width + "x" + height +
143
+ "&chco=" + primaryColor.replace("#", "") + "," +
144
+ shadowColor.replace("#", "") + "ff,ffffff01" +
145
+ "&chl=" + label + "&chx=" + labelColor.replace("#", "") +
146
+ "," + labelSize;
147
+ var icon = new GIcon(G_DEFAULT_ICON);
148
+ icon.image = iconUrl + "&chf=bg,s,00000000" + "&ext=.png";
149
+ icon.iconSize = new GSize(width, height);
150
+ icon.shadowSize = new GSize(0, 0);
151
+ icon.iconAnchor = new GPoint(width / 2, height / 2);
152
+ icon.infoWindowAnchor = new GPoint(width / 2, height / 2);
153
+ icon.printImage = iconUrl + "&chof=gif";
154
+ icon.mozPrintImage = iconUrl + "&chf=bg,s,ECECD8" + "&chof=gif";
155
+ icon.transparent = iconUrl + "&chf=a,s,ffffff01&ext=.png";
156
+ icon.imageMap = [];
157
+ if (shapeCode === "itr") {
158
+ icon.imageMap = [0, 0, width, 0, width, height, 0, height];
159
+ } else {
160
+ var polyNumSides = 8;
161
+ var polySideLength = 360 / polyNumSides;
162
+ var polyRadius = Math.min(width, height) / 2;
163
+ for (var a = 0; a < (polyNumSides + 1); a++) {
164
+ var aRad = polySideLength * a * (Math.PI / 180);
165
+ var pixelX = polyRadius + polyRadius * Math.cos(aRad);
166
+ var pixelY = polyRadius + polyRadius * Math.sin(aRad);
167
+ icon.imageMap.push(parseInt(pixelX), parseInt(pixelY));
168
+ }
169
+ }
170
+
171
+ return icon;
172
+ };
173
+
174
+
175
+ /**
176
+ * Creates a labeled marker icon based on the specified options in the
177
+ * {@link MarkerIconOptions} argument.
178
+ * Supported options are: primaryColor, strokeColor,
179
+ * starPrimaryColor, starStrokeColor, label, labelColor, and addStar.
180
+ * @param {MarkerIconOptions} [opts]
181
+ * @return {GIcon}
182
+ */
183
+ MapIconMaker.createLabeledMarkerIcon = function (opts) {
184
+ var primaryColor = opts.primaryColor || "#DA7187";
185
+ var strokeColor = opts.strokeColor || "#000000";
186
+ var starPrimaryColor = opts.starPrimaryColor || "#FFFF00";
187
+ var starStrokeColor = opts.starStrokeColor || "#0000FF";
188
+ var label = MapIconMaker.escapeUserText_(opts.label) || "";
189
+ var labelColor = opts.labelColor || "#000000";
190
+ var addStar = opts.addStar || false;
191
+
192
+ var pinProgram = (addStar) ? "pin_star" : "pin";
193
+ var baseUrl = "http://chart.apis.google.com/chart?cht=d&chdp=mapsapi&chl=";
194
+ var iconUrl = baseUrl + pinProgram + "'i\\" + "'[" + label +
195
+ "'-2'f\\" + "hv'a\\]" + "h\\]o\\" +
196
+ primaryColor.replace("#", "") + "'fC\\" +
197
+ labelColor.replace("#", "") + "'tC\\" +
198
+ strokeColor.replace("#", "") + "'eC\\";
199
+ if (addStar) {
200
+ iconUrl += starPrimaryColor.replace("#", "") + "'1C\\" +
201
+ starStrokeColor.replace("#", "") + "'0C\\";
202
+ }
203
+ iconUrl += "Lauto'f\\";
204
+
205
+ var icon = new GIcon(G_DEFAULT_ICON);
206
+ icon.image = iconUrl + "&ext=.png";
207
+ icon.iconSize = (addStar) ? new GSize(23, 39) : new GSize(21, 34);
208
+ return icon;
209
+ };
210
+
211
+
212
+ /**
213
+ * Utility function for doing special chart API escaping first,
214
+ * and then typical URL escaping. Must be applied to user-supplied text.
215
+ * @private
216
+ */
217
+ MapIconMaker.escapeUserText_ = function (text) {
218
+ if (text === undefined) {
219
+ return null;
220
+ }
221
+ text = text.replace(/@/, "@@");
222
+ text = text.replace(/\\/, "@\\");
223
+ text = text.replace(/'/, "@'");
224
+ text = text.replace(/\[/, "@[");
225
+ text = text.replace(/\]/, "@]");
226
+ return encodeURIComponent(text);
227
+ };
@@ -0,0 +1,44 @@
1
+ class <%= migration_name %> < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ create_table :<%= table_name %> do |t|
5
+ <% attributes.each do |attribute| -%>
6
+ t.<%= attribute.type %> :<%= attribute.name %>
7
+ <% end -%>
8
+ t.decimal :lat, :precision => 9, :scale => 6, :default => 0.0
9
+ t.decimal :lng, :precision => 9, :scale => 6, :default => 0.0
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :<%= table_name %>, :id
14
+
15
+ User.find(:all).each do |user|
16
+ user.plugins.create(:name => "Map", :position => (user.plugins.maximum(:position) || -1) + 1)
17
+ end
18
+
19
+ page = Page.create(:title => "Map",
20
+ :link_url => "/map",
21
+ :menu_match => "^/map.*$",
22
+ :deletable => false,
23
+ :position => Page.count)
24
+
25
+ RefinerySetting.find_or_set(:default_page_parts, ["Body", "Side Body"]).each do |default_page_part|
26
+ page.parts.create(:title => default_page_part, :body => nil)
27
+ end
28
+
29
+ end
30
+
31
+ def self.down
32
+ UserPlugin.destroy_all({:name => "Map"})
33
+
34
+ Page.find_all_by_link_url("/map").each do |page|
35
+ page.link_url, page.menu_match = nil
36
+ page.deletable = true
37
+ page.destroy
38
+ end
39
+ Page.destroy_all({:link_url => "/map"})
40
+
41
+ drop_table :<%= table_name %>
42
+ end
43
+
44
+ end
data/lib/gemspec.rb ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../map.rb', __FILE__)
3
+ version = ::Refinery::Map.version
4
+ raise "Could not get version so gemspec can not be built" if version.nil?
5
+ files = Dir.glob("**/*").flatten.reject do |file|
6
+ file =~ /\.gem(spec)?$/
7
+ end
8
+
9
+ gemspec = <<EOF
10
+ Gem::Specification.new do |s|
11
+ s.name = %q{refinerycms-map}
12
+ s.version = %q{#{version}}
13
+ s.description = %q{A RefineryCMS plugin that displays an interactive Google map with flaggable locations.}
14
+ s.date = %q{#{Time.now.strftime('%Y-%m-%d')}}
15
+ s.summary = %q{Ruby on Rails map engine for RefineryCMS.}
16
+ s.email = %q{lab@envylabs.com}
17
+ s.homepage = %q{http://github.com/envylabs/refinerycms-map}
18
+ s.authors = %w(Envy\\ Labs)
19
+ s.require_paths = %w(lib)
20
+
21
+ s.files = [
22
+ '#{files.join("',\n '")}'
23
+ ]
24
+ #{"s.test_files = [
25
+ '#{Dir.glob("test/**/*.rb").join("',\n '")}'
26
+ ]" if File.directory?("test")}
27
+ end
28
+ EOF
29
+
30
+ File.open(File.expand_path("../../refinerycms-map.gemspec", __FILE__), 'w').puts(gemspec)
data/lib/map.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Refinery
2
+ module Map
3
+ class << self
4
+ def version
5
+ %q{0.0.1}
6
+ end
7
+ end
8
+ end
9
+ end
data/license.md ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2005-2010 [Resolve Digital Ltd.](http://www.resolvedigital.co.nz)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/rails/init.rb ADDED
@@ -0,0 +1,13 @@
1
+ Refinery::Plugin.register do |plugin|
2
+ plugin.title = "Map"
3
+ plugin.description = "Provides a Google map with location markers"
4
+ plugin.version = 1.0
5
+ plugin.menu_match = /(admin|refinery)\/map(_locations)?$/
6
+ plugin.url = '/refinery/map'
7
+ plugin.activity = {
8
+ :class => MapLocation,
9
+ :title => 'title',
10
+ :url_prefix => 'edit'
11
+ }
12
+ plugin.directory = directory
13
+ end
data/readme.md ADDED
@@ -0,0 +1,39 @@
1
+ # Refinery CMS Map Plugin
2
+
3
+ ## About
4
+
5
+ __This plugin adds a Google map with any number of flagged locations.__
6
+
7
+ Key features:
8
+
9
+ * Admin interface allows you to set the locations that will be displayed on the map.
10
+ * Clicking a location on the map shows address, phone number, and url for that location.
11
+
12
+ ## How do I use it?
13
+
14
+ To install the map plugin, you can either include the gem or install as a plugin.
15
+
16
+ ## Requirements
17
+
18
+ [RefineryCMS](http://refinerycms.com) version 0.9.7 or later.
19
+
20
+ ### Gem Installation using Bundler
21
+
22
+ Include the latest [gem](http://rubygems.org/gems/refinerycms-map) into your Refinery CMS application's Gemfile:
23
+
24
+ gem "refinerycms-map", '~> 0.0.1', :require => "map"
25
+
26
+ Then type the following at command line inside your Refinery CMS application's root directory:
27
+
28
+ bundle install
29
+ script/generate map
30
+ rake db:migrate
31
+
32
+ ### Rails Engine Installation
33
+
34
+ If you do not want to install the engine via bundler then you can install it as an engine inside your application's vendor directory.
35
+ Type the following at command line inside your Refinery CMS application's root directory:
36
+
37
+ script/plugin install git://github.com/envylabs/refinerycms-map.git
38
+ script/generate map
39
+ rake db:migrate
@@ -0,0 +1,4 @@
1
+ require 'test_helper'
2
+
3
+ class MapLocationTest < ActiveSupport::TestCase
4
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: refinerycms-map
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Envy Labs
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-29 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: A RefineryCMS plugin that displays an interactive Google map with flaggable locations.
23
+ email: lab@envylabs.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - app/controllers/admin/map_locations_controller.rb
32
+ - app/controllers/map_locations_controller.rb
33
+ - app/models/map_location.rb
34
+ - app/views/admin/map_locations/_form.html.erb
35
+ - app/views/admin/map_locations/_map_location.html.erb
36
+ - app/views/admin/map_locations/edit.html.erb
37
+ - app/views/admin/map_locations/index.html.erb
38
+ - app/views/admin/map_locations/new.html.erb
39
+ - app/views/map_locations/index.html.erb
40
+ - app/views/map_locations/show.html.erb
41
+ - config/locales/en.yml
42
+ - config/routes.rb
43
+ - generators/map/map_generator.rb
44
+ - generators/map/templates/jquery.jmapping.min.js
45
+ - generators/map/templates/jquery.metadata.js
46
+ - generators/map/templates/mapiconmaker.js
47
+ - generators/map/templates/migration.rb
48
+ - lib/gemspec.rb
49
+ - lib/map.rb
50
+ - license.md
51
+ - rails/init.rb
52
+ - readme.md
53
+ - test/unit/map_location_test.rb
54
+ has_rdoc: true
55
+ homepage: http://github.com/envylabs/refinerycms-map
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Ruby on Rails map engine for RefineryCMS.
88
+ test_files:
89
+ - test/unit/map_location_test.rb