Merge branch 'migrate_ent_types' into bugfix

Conflicts:
	app/models/spree/ability_decorator.rb
This commit is contained in:
Rafael Schouten
2014-10-18 07:37:41 +11:00
105 changed files with 490 additions and 2653 deletions

View File

@@ -1,4 +1,5 @@
angular.module("admin.enterprises")
# Populate Enterprise.enterprise with enterprise json array from the page.
.factory 'Enterprise', (enterprise) ->
new class Enterprise
enterprise: enterprise
enterprise: enterprise

View File

@@ -1,13 +1,14 @@
Darkswarm.controller "HubsCtrl", ($scope, Hubs, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, MapModal) ->
$scope.Hubs = Hubs
$scope.hubs = Hubs.visible
Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, EnterpriseModal) ->
$scope.Enterprises = Enterprises
$scope.totalActive = FilterSelectorsService.totalActive
$scope.clearAll = FilterSelectorsService.clearAll
$scope.filterText = FilterSelectorsService.filterText
$scope.FilterSelectorsService = FilterSelectorsService
$scope.query = Search.search()
$scope.openModal = EnterpriseModal.open
$scope.activeTaxons = []
$scope.show_profiles = false
$scope.openModal = MapModal.open
$scope.filtersActive = false
$scope.$watch "query", (query)->
Search.search query

View File

@@ -1,14 +0,0 @@
Darkswarm.controller "ProducersCtrl", ($scope, Producers, $filter, FilterSelectorsService, Search, MapModal) ->
$scope.Producers = Producers
$scope.totalActive = FilterSelectorsService.totalActive
$scope.clearAll = FilterSelectorsService.clearAll
$scope.filterText = FilterSelectorsService.filterText
$scope.FilterSelectorsService = FilterSelectorsService
$scope.filtersActive = false
$scope.activeTaxons = []
$scope.query = Search.search()
$scope.show_profiles = false
$scope.openModal = MapModal.open
$scope.$watch "query", (query)->
Search.search query

View File

@@ -1,3 +1,4 @@
Darkswarm.controller "ProducersTabCtrl", ($scope, CurrentHub, Enterprises) ->
# Injecting Enterprises so CurrentHub.producers is dereferenced
Darkswarm.controller "ProducersTabCtrl", ($scope, CurrentHub, Enterprises, EnterpriseModal) ->
# Injecting Enterprises so CurrentHub.producers is dereferenced.
# We should probably dereference here instead and separate out CurrentHub dereferencing from the Enterprise factory.
$scope.CurrentHub = CurrentHub

View File

@@ -1,18 +1,11 @@
Darkswarm.controller "TabsCtrl", ($scope, $rootScope, $location, OrderCycle) ->
# Return active if supplied path matches url hash path.
$scope.active = (path)->
if !OrderCycle.selected() and $location.hash() == "" and path == "about"
true
else
$location.hash() == path
$location.hash() == path
$scope.tabs = ["contact", "about", "groups", "producers"]
for tab in $scope.tabs
$scope[tab] =
path: tab
$scope.select = (tab)->
if $scope.active(tab.path)
# Toggle tab selected status by setting the url hash path.
$scope.select = (path)->
if $scope.active(path)
$location.hash ""
else
$location.hash tab.path
$location.hash path

View File

@@ -1,4 +1,4 @@
Darkswarm.directive "producerModal", ($modal)->
Darkswarm.directive "enterpriseModal", ($modal)->
restrict: 'E'
replace: true
template: "<a ng-transclude></a>"
@@ -6,5 +6,4 @@ Darkswarm.directive "producerModal", ($modal)->
link: (scope, elem, attrs, ctrl)->
elem.on "click", (ev)=>
ev.stopPropagation()
scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'producer_modal.html', scope: scope)
scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'enterprise_modal.html', scope: scope)

View File

@@ -1,8 +0,0 @@
Darkswarm.directive "hubModal", ($modal)->
restrict: 'E'
replace: true
template: "<a>{{enterprise.name}}</a>"
link: (scope, elem, attrs, ctrl)->
elem.on "click", (ev)=>
ev.stopPropagation()
scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'hub_modal.html', scope: scope)

View File

@@ -1,4 +1,5 @@
Darkswarm.filter "capitalize", ->
# Convert to basic sentence case.
(input, scope) ->
input = input.toLowerCase() if input?
input = input.toLowerCase() if input?
input.substring(0, 1).toUpperCase() + input.substring(1)

View File

@@ -1,9 +0,0 @@
Darkswarm.filter 'hubs', (Matcher)->
(hubs, text) ->
hubs ||= []
text ?= ""
hubs.filter (hub)=>
Matcher.match [
hub.name, hub.address.zipcode, hub.address.city, hub.address.state
], text

View File

@@ -1,6 +0,0 @@
Darkswarm.filter 'filterProducers', (hubsFilter)->
(producers, text) ->
producers ||= []
text ?= ""
hubsFilter(producers, text)

View File

@@ -1,15 +1,14 @@
# Convert number to string currency using injected currency configuration.
#
# @requires currencyConfig json - /app/serializers/api/currency_config_serializer.rb
# @return: string
Darkswarm.filter "localizeCurrency", (currencyConfig)->
# Convert number to string currency using injected currency configuration.
(amount) ->
# Set country code (eg. "US").
currency_code = if currencyConfig.display_currency then " " + currencyConfig.currency else ""
# Set decimal points, 2 or 0 if hide_cents.
decimals = if currencyConfig.hide_cents == "true" then 0 else 2
# We need to use parseFloat before toFixed as the amount should be a passed in as a string.
# We need to use parseFloat before toFixed as the amount should come in as a string.
amount_fixed = parseFloat(amount).toFixed(decimals)
# Build the final price string.
# Build the final price string. TODO use spree decimal point and spacer character settings.
if currencyConfig.symbol_position == 'before'
currencyConfig.symbol + amount_fixed + currency_code
else

View File

@@ -0,0 +1,10 @@
Darkswarm.filter 'searchEnterprises', (Matcher)->
# Search multiple fields of enterprises for matching text fragment.
(enterprises, text) ->
enterprises ||= []
text ?= ""
enterprises.filter (enterprise)=>
Matcher.match [
enterprise.name, enterprise.address.zipcode, enterprise.address.city, enterprise.address.state
], text

View File

@@ -0,0 +1,8 @@
Darkswarm.filter 'showHubProfiles', ()->
# Filter hub_profile enterprises in or out.
(enterprises, show_profiles) ->
enterprises ||= []
show_profiles ?= false
enterprises.filter (enterprise)=>
show_profiles or enterprise.is_distributor

View File

@@ -1,7 +0,0 @@
Darkswarm.filter 'showProfiles', ()->
(enterprises, show_profiles) ->
enterprises ||= []
show_profiles ?= true
enterprises.filter (enterprise)=>
show_profiles or enterprise.has_shopfront

View File

@@ -1,13 +1,16 @@
Darkswarm.filter 'taxons', (Matcher)->
# Filter anything that responds to object.taxons, and/or object.primary_taxon
Darkswarm.filter 'taxons', ()->
# Filter anything that responds to object.taxons, object.supplied_taxon or object.primary_taxon.
(objects, ids) ->
objects ||= []
ids ?= []
if ids.length == 0
# No taxons selected, pass all objects through.
objects
else
objects.filter (obj)->
taxons = obj.taxons
taxons.concat obj.supplied_taxons if obj.supplied_taxons
# Combine object taxons with supplied taxons, if they exist.
taxons = taxons.concat obj.supplied_taxons if obj.supplied_taxons
# Match primary taxon if it exists, then taxon array.
obj.primary_taxon?.id in ids || taxons.some (taxon)->
taxon.id in ids

View File

@@ -1,3 +1,4 @@
Darkswarm.factory 'CurrentHub', ($location, $filter, currentHub) ->
Darkswarm.factory 'CurrentHub', (currentHub) ->
# Populate CurrentHub.hub from json in page. This is probably redundant now.
new class CurrentHub
hub: currentHub

View File

@@ -1,3 +1,4 @@
Darkswarm.factory 'CurrentOrder', (currentOrder) ->
# Populate Currentorder.order from json in page. This is probably redundant now.
new class CurrentOrder
order: currentOrder

View File

@@ -0,0 +1,8 @@
Darkswarm.factory "EnterpriseModal", ($modal, $rootScope)->
# Build a modal popup for an enterprise.
new class EnterpriseModal
open: (enterprise)->
scope = $rootScope.$new(true) # Spawn an isolate to contain the enterprise
scope.enterprise = enterprise
$modal.open(templateUrl: "enterprise_modal.html", scope: scope)

View File

@@ -1,13 +1,21 @@
Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer)->
Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter)->
new class Enterprises
enterprises_by_id: {} # id/object pairs for lookup
enterprises_by_id: {}
constructor: ->
# Populate Enterprises.enterprises from json in page.
@enterprises = enterprises
# Map enterprises to id/object pairs for lookup.
for enterprise in enterprises
@enterprises_by_id[enterprise.id] = enterprise
# Replace enterprise and taxons ids with actual objects.
@dereferenceEnterprises()
@dereferenceTaxons()
@visible_enterprises = visibleFilter @enterprises
@producers = @visible_enterprises.filter (enterprise)->
enterprise.category in ["producer_hub", "producer_shop", "producer"]
@hubs = @visible_enterprises.filter (enterprise)->
enterprise.category in ["hub", "hub_profile", "producer_hub", "producer_shop"]
dereferenceEnterprises: ->
if CurrentHub.hub?.id
CurrentHub.hub = @enterprises_by_id[CurrentHub.hub.id]
@@ -16,6 +24,7 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer)
Dereferencer.dereference enterprise.producers, @enterprises_by_id
dereferenceTaxons: ->
for enterprise in @enterprises
for enterprise in @enterprises
Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id
Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id

View File

@@ -1,9 +0,0 @@
Darkswarm.factory 'Hubs', ($filter, Enterprises, visibleFilter) ->
new class Hubs
constructor: ->
@hubs = @order Enterprises.enterprises.filter (hub)->
hub.has_hub_listing
@visible = visibleFilter @hubs
order: (hubs)->
$filter('orderBy')(hubs, ['-active', '+orders_close_at'])

View File

@@ -1,7 +1,7 @@
Darkswarm.factory "OfnMap", (Enterprises, MapModal, visibleFilter)->
Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal, visibleFilter)->
new class OfnMap
constructor: ->
@enterprises = (@extend(enterprise) for enterprise in visibleFilter(Enterprises.enterprises))
@enterprises = (@extend(enterprise) for enterprise in visibleFilter(Enterprises.enterprises))
# Adding methods to each enterprise
@@ -14,4 +14,4 @@ Darkswarm.factory "OfnMap", (Enterprises, MapModal, visibleFilter)->
icon: enterprise.icon
id: enterprise.id
reveal: =>
MapModal.open enterprise
EnterpriseModal.open enterprise

View File

@@ -1,12 +0,0 @@
Darkswarm.factory "MapModal", ($modal, $rootScope)->
new class MapModal
open: (enterprise)->
scope = $rootScope.$new(true) # Spawn an isolate to contain the enterprise
scope.enterprise = enterprise
if enterprise.is_distributor
scope.hub = enterprise
$modal.open(templateUrl: "hub_modal.html", scope: scope)
else
scope.producer = enterprise
$modal.open(templateUrl: "map_modal_producer.html", scope: scope)

View File

@@ -1,6 +1,7 @@
Darkswarm.factory "Matcher", ->
new class Matcher
match: (properties, text)->
properties.some (prop)->
prop ||= ""
prop.toLowerCase().indexOf(text.toLowerCase()) != -1
# Match text fragment in an array of strings.
new class Matcher
match: (properties, text)->
properties.some (prop)->
prop ||= ""
prop.toLowerCase().indexOf(text.toLowerCase()) != -1

View File

@@ -1,7 +0,0 @@
Darkswarm.factory 'Producers', (Enterprises, visibleFilter) ->
new class Producers
constructor: ->
@producers = Enterprises.enterprises.filter (enterprise)->
enterprise.is_primary_producer
@visible = visibleFilter @producers

View File

@@ -1,8 +1,10 @@
Darkswarm.factory "Taxons", (taxons)->
new class Taxons
taxons: taxons
# Populate Taxons.taxons from json in page.
taxons: taxons
taxons_by_id: {}
constructor: ->
# Map taxons to id/object pairs for lookup.
for taxon in @taxons
@taxons_by_id[taxon.id] = taxon

View File

@@ -5,6 +5,7 @@ Darkswarm.factory 'Variants', ->
@variants[variant.id] ||= @extend variant
extend: (variant)->
# Add totalPrice method to calculate line item total. This should be on a line item!
variant.totalPrice = ->
variant.price_with_fees * variant.line_item.quantity
variant.basePricePercentage = Math.round(variant.price / variant.price_with_fees * 100)

View File

@@ -1,18 +0,0 @@
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require spin
//= require foundation
//= require_tree .
//
// Hacky fix for issue - http://foundation.zurb.com/forum/posts/2112-foundation-5100-syntax-error-in-js
Foundation.set_namespace = function() {};
$(function(){ $(document).foundation(); });

View File

@@ -1,444 +0,0 @@
Gmaps = {}
Gmaps.triggerOldOnload = ->
Gmaps.oldOnload() if typeof(Gmaps.oldOnload) == 'function'
Gmaps.loadMaps = ->
#loop through all variable names.
#there should only be maps inside so it trigger their load function
for key, value of Gmaps
searchLoadIncluded = key.search(/load/)
if searchLoadIncluded == -1
load_function_name = "load_" + key
Gmaps[load_function_name]()
window.Gmaps = Gmaps
class @Gmaps4Rails
constructor: ->
#map config
@map = null #DEPRECATED: will still contain a copy of serviceObject below as transition
@serviceObject = null #contains the map we're working on
@visibleInfoWindow = null #contains the current opened infowindow
@userLocation = null #contains user's location if geolocalization was performed and successful
#empty slots
@geolocationSuccess = -> false #triggered when geolocation succeeds. Can be customized.
@geolocationFailure = -> false #triggered when geolocation fails. If customized, must be like= function(navigator_handles_geolocation){} where 'navigator_handles_geolocation' is a boolean
@callback = -> false #to let user set a custom callback function
@customClusterer = -> false #to let user set custom clusterer pictures
@infobox = -> false #to let user use custom infoboxes
@jsTemplate = false #to let user create infowindows client side
@default_map_options =
id: 'map'
draggable: true
detect_location: false # should the browser attempt to use geolocation detection features of HTML5?
center_on_user: false # centers map on the location detected through the browser
center_latitude: 0
center_longitude: 0
zoom: 7
maxZoom: null
minZoom: null
auto_adjust : true # adjust the map to the markers if set to true
auto_zoom: true # zoom given by auto-adjust
bounds: [] # adjust map to these limits. Should be [{"lat": , "lng": }]
raw: {} # raw json to pass additional options
@default_markers_conf =
#Marker config
title: ""
#MarkerImage config
picture : ""
width: 22
length: 32
draggable: false # how to modify: <%= gmaps( "markers" => { "data" => @object.to_gmaps4rails, "options" => { "draggable" => true }}) %>
#clustering config
do_clustering: false # do clustering if set to true
randomize: false # Google maps can't display two markers which have the same coordinates. This randomizer enables to prevent this situation from happening.
max_random_distance: 100 # in meters. Each marker coordinate could be altered by this distance in a random direction
list_container: null # id of the ul that will host links to all markers
offset: 0 # used when adding_markers to an existing map. Because new markers are concated with previous one, offset is here to prevent the existing from being re-created.
raw: {} # raw json to pass additional options
#Stored variables
@markers = [] # contains all markers. A marker contains the following: {"description": , "longitude": , "title":, "latitude":, "picture": "", "width": "", "length": "", "sidebar": "", "serviceObject": google_marker}
@boundsObject = null # contains current bounds from markers, polylines etc...
@polygons = [] # contains raw data, array of arrays (first element could be a hash containing options)
@polylines = [] # contains raw data, array of arrays (first element could be a hash containing options)
@circles = [] # contains raw data, array of hash
@markerClusterer = null # contains all marker clusterers
@markerImages = []
#Polyline Styling
@polylines_conf = #default style for polylines
strokeColor: "#FF0000"
strokeOpacity: 1
strokeWeight: 2
clickable: false
zIndex: null
#tnitializes the map
initialize : ->
@serviceObject = @createMap()
@map = @serviceObject #beware, soon deprecated
if (@map_options.detect_location == true or @map_options.center_on_user == true)
@findUserLocation(this)
#resets sidebar if needed
@resetSidebarContent()
findUserLocation : (map_object) ->
if (navigator.geolocation)
#try to retrieve user's position
positionSuccessful = (position) ->
map_object.userLocation = map_object.createLatLng(position.coords.latitude, position.coords.longitude)
#change map's center to focus on user's geoloc if asked
if(map_object.map_options.center_on_user == true)
map_object.centerMapOnUser()
map_object.geolocationSuccess()
positionFailure = ->
map_object.geolocationFailure(true)
navigator.geolocation.getCurrentPosition( positionSuccessful, positionFailure)
else
#failure but the navigator doesn't handle geolocation
map_object.geolocationFailure(false)
#////////////////////////////////////////////////////
#//////////////////// DIRECTIONS ////////////////////
#////////////////////////////////////////////////////
create_direction : ->
directionsDisplay = new google.maps.DirectionsRenderer()
directionsService = new google.maps.DirectionsService()
directionsDisplay.setMap(@serviceObject)
#display panel only if required
if @direction_conf.display_panel
directionsDisplay.setPanel(document.getElementById(@direction_conf.panel_id))
directionsDisplay.setOptions
suppressMarkers: false
suppressInfoWindows: false
suppressPolylines: false
request =
origin: @direction_conf.origin
destination: @direction_conf.destination
waypoints: @direction_conf.waypoints
optimizeWaypoints: @direction_conf.optimizeWaypoints
unitSystem: google.maps.DirectionsUnitSystem[@direction_conf.unitSystem]
avoidHighways: @direction_conf.avoidHighways
avoidTolls: @direction_conf.avoidTolls
region: @direction_conf.region
travelMode: google.maps.DirectionsTravelMode[@direction_conf.travelMode]
language: "en"
directionsService.route request, (response, status) ->
if (status == google.maps.DirectionsStatus.OK)
directionsDisplay.setDirections(response)
#////////////////////////////////////////////////////
#///////////////////// CIRCLES //////////////////////
#////////////////////////////////////////////////////
#Loops through all circles
#Loops through all circles and draws them
create_circles : ->
for circle in @circles
@create_circle circle
create_circle : (circle) ->
#by convention, default style configuration could be integrated in the first element
if circle == @circles[0]
@circles_conf.strokeColor = circle.strokeColor if circle.strokeColor?
@circles_conf.strokeOpacity = circle.strokeOpacity if circle.strokeOpacity?
@circles_conf.strokeWeight = circle.strokeWeight if circle.strokeWeight?
@circles_conf.fillColor = circle.fillColor if circle.fillColor?
@circles_conf.fillOpacity = circle.fillOpacity if circle.fillOpacity?
if circle.lat? and circle.lng?
# always check if a config is given, if not, use defaults
# NOTE: is there a cleaner way to do this? Maybe a hash merge of some sort?
newCircle = new google.maps.Circle
center: @createLatLng(circle.lat, circle.lng)
strokeColor: circle.strokeColor || @circles_conf.strokeColor
strokeOpacity: circle.strokeOpacity || @circles_conf.strokeOpacity
strokeWeight: circle.strokeWeight || @circles_conf.strokeWeight
fillOpacity: circle.fillOpacity || @circles_conf.fillOpacity
fillColor: circle.fillColor || @circles_conf.fillColor
clickable: circle.clickable || @circles_conf.clickable
zIndex: circle.zIndex || @circles_conf.zIndex
radius: circle.radius
circle.serviceObject = newCircle
newCircle.setMap(@serviceObject)
# clear circles
clear_circles : ->
for circle in @circles
@clear_circle circle
clear_circle : (circle) ->
circle.serviceObject.setMap(null)
hide_circles : ->
for circle in @circles
@hide_circle circle
hide_circle : (circle) ->
circle.serviceObject.setMap(null)
show_circles : ->
for circle in @circles
@show_circle @circle
show_circle : (circle) ->
circle.serviceObject.setMap(@serviceObject)
#////////////////////////////////////////////////////
#///////////////////// POLYGONS /////////////////////
#////////////////////////////////////////////////////
#polygons is an array of arrays. It loops.
create_polygons : ->
for polygon in @polygons
@create_polygon(polygon)
#creates a single polygon, triggered by create_polygons
create_polygon : (polygon) ->
polygon_coordinates = []
#Polygon points are in an Array, that's why looping is necessary
for point in polygon
latlng = @createLatLng(point.lat, point.lng)
polygon_coordinates.push(latlng)
#first element of an Array could contain specific configuration for this particular polygon. If no config given, use default
if point == polygon[0]
strokeColor = point.strokeColor || @polygons_conf.strokeColor
strokeOpacity = point.strokeOpacity || @polygons_conf.strokeOpacity
strokeWeight = point.strokeWeight || @polygons_conf.strokeWeight
fillColor = point.fillColor || @polygons_conf.fillColor
fillOpacity = point.fillOpacity || @polygons_conf.fillOpacity
clickable = point.clickable || @polygons_conf.clickable
#Construct the polygon
new_poly = new google.maps.Polygon
paths: polygon_coordinates
strokeColor: strokeColor
strokeOpacity: strokeOpacity
strokeWeight: strokeWeight
fillColor: fillColor
fillOpacity: fillOpacity
clickable: clickable
map: @serviceObject
#save polygon in list
polygon.serviceObject = new_poly
#////////////////////////////////////////////////////
#///////////////////// MARKERS //////////////////////
#////////////////////////////////////////////////////
#creates, clusterizes and adjusts map
create_markers : ->
@createServiceMarkersFromMarkers()
@clusterize()
#create google.maps Markers from data provided by user
createServiceMarkersFromMarkers : ->
for marker, index in @markers
if not @markers[index].serviceObject?
#extract options, test if value passed or use default
Lat = @markers[index].lat
Lng = @markers[index].lng
#alter coordinates if randomize is true
if @markers_conf.randomize
LatLng = @randomize(Lat, Lng)
#retrieve coordinates from the array
Lat = LatLng[0]
Lng = LatLng[1]
#save object
@markers[index].serviceObject = @createMarker
"marker_picture": if @markers[index].picture then @markers[index].picture else @markers_conf.picture
"marker_width": if @markers[index].width then @markers[index].width else @markers_conf.width
"marker_height": if @markers[index].height then @markers[index].height else @markers_conf.length
"marker_title": if @markers[index].title then @markers[index].title else null
"marker_anchor": if @markers[index].marker_anchor then @markers[index].marker_anchor else null
"shadow_anchor": if @markers[index].shadow_anchor then @markers[index].shadow_anchor else null
"shadow_picture": if @markers[index].shadow_picture then @markers[index].shadow_picture else null
"shadow_width": if @markers[index].shadow_width then @markers[index].shadow_width else null
"shadow_height": if @markers[index].shadow_height then @markers[index].shadow_height else null
"marker_draggable": if @markers[index].draggable then @markers[index].draggable else @markers_conf.draggable
"rich_marker": if @markers[index].rich_marker then @markers[index].rich_marker else null
"zindex": if @markers[index].zindex then @markers[index].zindex else null
"Lat": Lat
"Lng": Lng
"index": index
#add infowindowstuff if enabled
@createInfoWindow(@markers[index])
#create sidebar if enabled
@createSidebar(@markers[index])
@markers_conf.offset = @markers.length
#creates Image Anchor Position or return null if nothing passed
createImageAnchorPosition : (anchorLocation) ->
if (anchorLocation == null)
return null
else
return @createPoint(anchorLocation[0], anchorLocation[1])
#replace old markers with new markers on an existing map
replaceMarkers : (new_markers, adjustBounds = true) ->
@clearMarkers()
#reset previous markers
@markers = new Array
#reset current bounds
@boundsObject = @createLatLngBounds() if adjustBounds
#reset sidebar content if exists
@resetSidebarContent()
#add new markers
@markers_conf.offset = 0
@addMarkers(new_markers, adjustBounds)
#add new markers to on an existing map
addMarkers : (new_markers, adjustBounds = true) ->
#update the list of markers to take into account
@markers = @markers.concat(new_markers)
#put markers on the map
@create_markers()
@adjustMapToBounds() if adjustBounds
#////////////////////////////////////////////////////
#///////////////////// SIDEBAR //////////////////////
#////////////////////////////////////////////////////
#//creates sidebar
createSidebar : (marker_container) ->
if (@markers_conf.list_container)
ul = document.getElementById(@markers_conf.list_container)
li = document.createElement('li')
aSel = document.createElement('a')
aSel.href = 'javascript:void(0);'
html = if marker_container.sidebar? then marker_container.sidebar else "Marker"
aSel.innerHTML = html
currentMap = this
aSel.onclick = @sidebar_element_handler(currentMap, marker_container.serviceObject, 'click')
li.appendChild(aSel)
ul.appendChild(li)
#moves map to marker clicked + open infowindow
sidebar_element_handler : (currentMap, marker, eventType) ->
return () ->
currentMap.map.panTo(marker.position)
google.maps.event.trigger(marker, eventType)
resetSidebarContent : ->
if @markers_conf.list_container isnt null
ul = document.getElementById(@markers_conf.list_container)
ul.innerHTML = ""
#////////////////////////////////////////////////////
#////////////////// MISCELLANEOUS ///////////////////
#////////////////////////////////////////////////////
#to make the map fit the different LatLng points
adjustMapToBounds : ->
#FIRST_STEP: retrieve all bounds
#create the bounds object only if necessary
if @map_options.auto_adjust or @map_options.bounds isnt null
@boundsObject = @createLatLngBounds()
#if autodjust is true, must get bounds from markers polylines etc...
if @map_options.auto_adjust
#from markers
@extendBoundsWithMarkers()
#from polylines:
@updateBoundsWithPolylines()
#from polygons:
@updateBoundsWithPolygons()
#from circles
@updateBoundsWithCircles()
#in every case, I've to take into account the bounds set up by the user
@extendMapBounds()
#SECOND_STEP: ajust the map to the bounds
@adaptMapToBounds()
#////////////////////////////////////////////////////
#/////////////////// POLYLINES //////////////////////
#////////////////////////////////////////////////////
#replace old markers with new markers on an existing map
replacePolylines : (new_polylines) ->
#reset previous polylines and kill them from map
@destroy_polylines()
#set new polylines
@polylines = new_polylines
#create
@create_polylines()
#.... and adjust map boundaries
@adjustMapToBounds()
destroy_polylines : ->
for polyline in @polylines
#delete polylines from map
polyline.serviceObject.setMap(null)
#empty array
@polylines = []
#polylines is an array of arrays. It loops.
create_polylines : ->
for polyline in @polylines
@create_polyline polyline
#////////////////////////////////////////////////////
#///////////////// Basic functions //////////////////
#///////////////////tests coded//////////////////////
#//basic function to check existence of a variable
exists : (var_name) ->
return (var_name != "" and typeof var_name != "undefined")
#randomize
randomize : (Lat0, Lng0) ->
#distance in meters between 0 and max_random_distance (positive or negative)
dx = @markers_conf.max_random_distance * @random()
dy = @markers_conf.max_random_distance * @random()
Lat = parseFloat(Lat0) + (180/Math.PI)*(dy/6378137)
Lng = parseFloat(Lng0) + ( 90/Math.PI)*(dx/6378137)/Math.cos(Lat0)
return [Lat, Lng]
mergeObjectWithDefault : (object1, object2) ->
copy_object1 = {}
for key, value of object1
copy_object1[key] = value
for key, value of object2
unless copy_object1[key]?
copy_object1[key] = value
return copy_object1
mergeWithDefault : (objectName) ->
default_object = @["default_" + objectName]
object = @[objectName]
@[objectName] = @mergeObjectWithDefault(object, default_object)
return true
#gives a value between -1 and 1
random : -> return(Math.random() * 2 -1)

View File

@@ -1,174 +0,0 @@
######################################################################################################
############################################## Bing Maps ##########################################
######################################################################################################
#// http://wiki.openstreetmap.org/wiki/OpenLayers
#// http://openlayers.org/dev/examples
#//http://docs.openlayers.org/contents.html
class @Gmaps4RailsBing extends Gmaps4Rails
constructor: ->
super
@map_options =
type: "road" # aerial, auto, birdseye, collinsBart, mercator, ordnanceSurvey, road
@markers_conf =
infobox: "description" #description or htmlContent
@mergeWithDefault("map_options")
@mergeWithDefault("markers_conf")
#////////////////////////////////////////////////////
#/////////////// Basic Objects //////////////
#////////////////////////////////////////////////////
getMapType: ->
switch @map_options.type
when "road" then return Microsoft.Maps.MapTypeId.road
when "aerial" then return Microsoft.Maps.MapTypeId.aerial
when "auto" then return Microsoft.Maps.MapTypeId.auto
when "birdseye" then return Microsoft.Maps.MapTypeId.birdseye
when "collinsBart" then return Microsoft.Maps.MapTypeId.collinsBart
when "mercator" then return Microsoft.Maps.MapTypeId.mercator
when "ordnanceSurvey" then return Microsoft.Maps.MapTypeId.ordnanceSurvey
else return Microsoft.Maps.MapTypeId.auto
createPoint: (lat, lng) ->
return new Microsoft.Maps.Point(lat, lng)
createLatLng:(lat, lng) ->
return new Microsoft.Maps.Location(lat, lng)
createLatLngBounds: ->
createMap: ->
return new Microsoft.Maps.Map(document.getElementById(@map_options.id), {
credentials: @map_options.provider_key,
mapTypeId: @getMapType(),
center: @createLatLng(@map_options.center_latitude, @map_options.center_longitude),
zoom: @map_options.zoom
})
createSize: (width, height) ->
return new google.maps.Size(width, height)
#////////////////////////////////////////////////////
#////////////////////// Markers /////////////////////
#////////////////////////////////////////////////////
createMarker: (args) ->
markerLatLng = @createLatLng(args.Lat, args.Lng)
marker
#// Marker sizes are expressed as a Size of X,Y
if args.marker_picture == ""
marker = new Microsoft.Maps.Pushpin(@createLatLng(args.Lat, args.Lng), {
draggable: args.marker_draggable,
anchor: @createImageAnchorPosition(args.Lat, args.Lng),
text: args.marker_title
}
);
else
marker = new Microsoft.Maps.Pushpin(@createLatLng(args.Lat, args.Lng), {
draggable: args.marker_draggable,
anchor: @createImageAnchorPosition(args.Lat, args.Lng),
icon: args.marker_picture,
height: args.marker_height,
text: args.marker_title,
width: args.marker_width
}
);
@addToMap(marker)
return marker
#// clear markers
clearMarkers: ->
for marker in @markers
@clearMarker marker
clearMarker: (marker) ->
@removeFromMap(marker.serviceObject)
#//show and hide markers
showMarkers: ->
for marker in @markers
@showMarker marker
showMarker: (marker) ->
marker.serviceObject.setOptions({ visible: true })
hideMarkers: ->
for marker in @markers
@hideMarker marker
hideMarker: (marker) ->
marker.serviceObject.setOptions({ visible: false })
extendBoundsWithMarkers: ->
locationsArray = []
for marker in @markers
locationsArray.push(marker.serviceObject.getLocation())
@boundsObject = Microsoft.Maps.LocationRect.fromLocations(locationsArray)
#////////////////////////////////////////////////////
#/////////////////// Clusterer //////////////////////
#////////////////////////////////////////////////////
createClusterer: (markers_array) ->
clearClusterer: ->
#//creates clusters
clusterize: ->
#////////////////////////////////////////////////////
#/////////////////// INFO WINDOW ////////////////////
#////////////////////////////////////////////////////
#// creates infowindows
createInfoWindow: (marker_container) ->
if marker_container.description?
#//create the infowindow
if @markers_conf.infobox == "description"
marker_container.info_window = new Microsoft.Maps.Infobox(marker_container.serviceObject.getLocation(), { description: marker_container.description, visible: false, showCloseButton: true})
else
marker_container.info_window = new Microsoft.Maps.Infobox(marker_container.serviceObject.getLocation(), { htmlContent: marker_container.description, visible: false})
#//add the listener associated
currentMap = this
Microsoft.Maps.Events.addHandler(marker_container.serviceObject, 'click', @openInfoWindow(currentMap, marker_container.info_window))
@addToMap(marker_container.info_window)
openInfoWindow: (currentMap, infoWindow) ->
return ->
# Close the latest selected marker before opening the current one.
if currentMap.visibleInfoWindow
currentMap.visibleInfoWindow.setOptions({ visible: false })
infoWindow.setOptions({ visible:true })
currentMap.visibleInfoWindow = infoWindow
#////////////////////////////////////////////////////
#/////////////////// Other methods //////////////////
#////////////////////////////////////////////////////
fitBounds: ->
@serviceObject.setView({bounds: @boundsObject})
addToMap: (object)->
@serviceObject.entities.push(object)
removeFromMap: (object)->
@serviceObject.entities.remove(object)
centerMapOnUser: ->
@serviceObject.setView({ center: @userLocation})
updateBoundsWithPolylines: ()->
updateBoundsWithPolygons: ()->
updateBoundsWithCircles: ()->
extendMapBounds :->
adaptMapToBounds: ->
@fitBounds()

View File

@@ -1,339 +0,0 @@
#######################################################################################################
############################################## Google maps ##########################################
#######################################################################################################
class @Gmaps4RailsGoogle extends Gmaps4Rails
constructor: ->
super
#Map settings
@map_options =
disableDefaultUI: false
disableDoubleClickZoom: false
type: "ROADMAP" # HYBRID, ROADMAP, SATELLITE, TERRAIN
#markers + info styling
@markers_conf =
clusterer_gridSize: 50
clusterer_maxZoom: 5
custom_cluster_pictures: null
custom_infowindow_class: null
@mergeWithDefault("map_options")
@mergeWithDefault("markers_conf")
@kml_options =
clickable: true
preserveViewport: false
suppressInfoWindows: false
#Polygon Styling
@polygons_conf = # default style for polygons
strokeColor: "#FFAA00"
strokeOpacity: 0.8
strokeWeight: 2
fillColor: "#000000"
fillOpacity: 0.35
clickable: false
#Circle Styling
@circles_conf = #default style for circles
fillColor: "#00AAFF"
fillOpacity: 0.35
strokeColor: "#FFAA00"
strokeOpacity: 0.8
strokeWeight: 2
clickable: false
zIndex: null
#Direction Settings
@direction_conf =
panel_id: null
display_panel: false
origin: null
destination: null
waypoints: [] #[{location: "toulouse,fr", stopover: true}, {location: "Clermont-Ferrand, fr", stopover: true}]
optimizeWaypoints: false
unitSystem: "METRIC" #IMPERIAL
avoidHighways: false
avoidTolls: false
region: null
travelMode: "DRIVING" #WALKING, BICYCLING
#////////////////////////////////////////////////////
#/////////////// Basic Objects //////////////
#////////////////////////////////////////////////////
createPoint : (lat, lng) ->
return new google.maps.Point(lat, lng)
createLatLng : (lat, lng) ->
return new google.maps.LatLng(lat, lng)
createLatLngBounds : ->
return new google.maps.LatLngBounds()
createMap : ->
defaultOptions =
maxZoom: @map_options.maxZoom
minZoom: @map_options.minZoom
zoom: @map_options.zoom
center: @createLatLng(@map_options.center_latitude, @map_options.center_longitude)
mapTypeId: google.maps.MapTypeId[@map_options.type]
mapTypeControl: @map_options.mapTypeControl
disableDefaultUI: @map_options.disableDefaultUI
disableDoubleClickZoom: @map_options.disableDoubleClickZoom
draggable: @map_options.draggable
mergedOptions = @mergeObjectWithDefault @map_options.raw, defaultOptions
return new google.maps.Map document.getElementById(@map_options.id), mergedOptions
createMarkerImage : (markerPicture, markerSize, origin, anchor, scaledSize) ->
return new google.maps.MarkerImage(markerPicture, markerSize, origin, anchor, scaledSize)
createSize : (width, height) ->
return new google.maps.Size(width, height)
#////////////////////////////////////////////////////
#////////////////////// Markers /////////////////////
#////////////////////////////////////////////////////
createMarker : (args) ->
markerLatLng = @createLatLng(args.Lat, args.Lng)
#Marker sizes are expressed as a Size of X,Y
if args.marker_picture == "" and args.rich_marker == null
defaultOptions = {position: markerLatLng, map: @serviceObject, title: args.marker_title, draggable: args.marker_draggable, zIndex: args.zindex}
mergedOptions = @mergeObjectWithDefault @markers_conf.raw, defaultOptions
return new google.maps.Marker mergedOptions
if (args.rich_marker != null)
return new RichMarker({
position: markerLatLng
map: @serviceObject
draggable: args.marker_draggable
content: args.rich_marker
flat: if args.marker_anchor == null then false else args.marker_anchor[1]
anchor: if args.marker_anchor == null then 0 else args.marker_anchor[0]
zIndex: args.zindex
})
#default behavior
#calculate MarkerImage anchor location
imageAnchorPosition = @createImageAnchorPosition args.marker_anchor
shadowAnchorPosition = @createImageAnchorPosition args.shadow_anchor
#create or retrieve existing MarkerImages
markerImage = @createOrRetrieveImage(args.marker_picture, args.marker_width, args.marker_height, imageAnchorPosition)
shadowImage = @createOrRetrieveImage(args.shadow_picture, args.shadow_width, args.shadow_height, shadowAnchorPosition)
defaultOptions = {position: markerLatLng, map: @serviceObject, icon: markerImage, title: args.marker_title, draggable: args.marker_draggable, shadow: shadowImage, zIndex: args.zindex}
mergedOptions = @mergeObjectWithDefault @markers_conf.raw, defaultOptions
return new google.maps.Marker mergedOptions
#checks if obj is included in arr Array and returns the position or false
includeMarkerImage : (arr, obj) ->
for object, index in arr
return index if object.url == obj
return false
#checks if MarkerImage exists before creating a new one
#returns a MarkerImage or false if ever something wrong is passed as argument
createOrRetrieveImage : (currentMarkerPicture, markerWidth, markerHeight, imageAnchorPosition) ->
return null if (currentMarkerPicture == "" or currentMarkerPicture == null )
test_image_index = @includeMarkerImage(@markerImages, currentMarkerPicture)
switch test_image_index
when false
markerImage = @createMarkerImage(currentMarkerPicture, @createSize(markerWidth, markerHeight), null, imageAnchorPosition, null )
@markerImages.push(markerImage)
return markerImage
break
else
return @markerImages[test_image_index] if typeof test_image_index == 'number'
return false
#clear markers
clearMarkers : ->
for marker in @markers
@clearMarker marker
#show and hide markers
showMarkers : ->
for marker in @markers
@showMarker marker
hideMarkers : ->
for marker in @markers
@hideMarker marker
clearMarker : (marker) ->
marker.serviceObject.setMap(null)
showMarker : (marker) ->
marker.serviceObject.setVisible(true)
hideMarker : (marker) ->
marker.serviceObject.setVisible(false)
extendBoundsWithMarkers : ->
for marker in @markers
@boundsObject.extend(marker.serviceObject.position)
#////////////////////////////////////////////////////
#/////////////////// Clusterer //////////////////////
#////////////////////////////////////////////////////
createClusterer : (markers_array) ->
return new MarkerClusterer( @serviceObject, markers_array, { maxZoom: @markers_conf.clusterer_maxZoom, gridSize: @markers_conf.clusterer_gridSize, styles: @customClusterer() })
clearClusterer : ->
@markerClusterer.clearMarkers()
#creates clusters
clusterize : ->
if @markers_conf.do_clustering == true
#first clear the existing clusterer if any
@clearClusterer() if @markerClusterer != null
markers_array = new Array
for marker in @markers
markers_array.push(marker.serviceObject)
@markerClusterer = @createClusterer(markers_array)
#////////////////////////////////////////////////////
#/////////////////// INFO WINDOW ////////////////////
#////////////////////////////////////////////////////
#// creates infowindows
createInfoWindow : (marker_container) ->
if typeof(@jsTemplate) == "function" or marker_container.description?
marker_container.description = @jsTemplate(marker_container) if typeof(@jsTemplate) == "function"
if @markers_conf.custom_infowindow_class != null
#creating custom infowindow
boxText = document.createElement("div")
boxText.setAttribute("class", @markers_conf.custom_infowindow_class) #to customize
boxText.innerHTML = marker_container.description
marker_container.infowindow = new InfoBox(@infobox(boxText))
currentMap = this
google.maps.event.addListener(marker_container.serviceObject, 'click', @openInfoWindow(currentMap, marker_container.infowindow, marker_container.serviceObject))
else
#create default infowindow
marker_container.infowindow = new google.maps.InfoWindow({content: marker_container.description })
#add the listener associated
currentMap = this
google.maps.event.addListener(marker_container.serviceObject, 'click', @openInfoWindow(currentMap, marker_container.infowindow, marker_container.serviceObject))
openInfoWindow : (currentMap, infoWindow, marker) ->
return ->
# Close the latest selected marker before opening the current one.
currentMap.visibleInfoWindow.close() if currentMap.visibleInfoWindow != null
infoWindow.open(currentMap.serviceObject, marker)
currentMap.visibleInfoWindow = infoWindow
#////////////////////////////////////////////////////
#///////////////// KML //////////////////
#////////////////////////////////////////////////////
createKmlLayer : (kml) ->
kml_options = kml.options || {}
kml_options = @mergeObjectWithDefault(kml_options, @kml_options)
kml = new google.maps.KmlLayer( kml.url, kml_options)
kml.setMap(@serviceObject)
return kml
#////////////////////////////////////////////////////
#/////////////////// POLYLINES //////////////////////
#////////////////////////////////////////////////////
#creates a single polyline, triggered by create_polylines
create_polyline : (polyline) ->
polyline_coordinates = []
#2 cases here, either we have a coded array of LatLng or we have an Array of LatLng
for element in polyline
#if we have a coded array
if element.coded_array?
decoded_array = new google.maps.geometry.encoding.decodePath(element.coded_array)
#loop through every point in the array
for point in decoded_array
polyline_coordinates.push(point)
#or we have an array of latlng
else
#by convention, a single polyline could be customized in the first array or it uses default values
if element == polyline[0]
strokeColor = element.strokeColor || @polylines_conf.strokeColor
strokeOpacity = element.strokeOpacity || @polylines_conf.strokeOpacity
strokeWeight = element.strokeWeight || @polylines_conf.strokeWeight
clickable = element.clickable || @polylines_conf.clickable
zIndex = element.zIndex || @polylines_conf.zIndex
#add latlng if positions provided
if element.lat? && element.lng?
latlng = @createLatLng(element.lat, element.lng)
polyline_coordinates.push(latlng)
# Construct the polyline
new_poly = new google.maps.Polyline
path: polyline_coordinates
strokeColor: strokeColor
strokeOpacity: strokeOpacity
strokeWeight: strokeWeight
clickable: clickable
zIndex: zIndex
#save polyline
polyline.serviceObject = new_poly
new_poly.setMap(@serviceObject)
updateBoundsWithPolylines: ()->
for polyline in @polylines
polyline_points = polyline.serviceObject.latLngs.getArray()[0].getArray()
for point in polyline_points
@boundsObject.extend point
#////////////////////////////////////////////////////
#///////////////// KML //////////////////
#////////////////////////////////////////////////////
create_kml : ->
for kml in @kml
kml.serviceObject = @createKmlLayer kml
#////////////////////////////////////////////////////
#/////////////////// Other methods //////////////////
#////////////////////////////////////////////////////
fitBounds : ->
@serviceObject.fitBounds(@boundsObject) unless @boundsObject.isEmpty()
centerMapOnUser : ->
@serviceObject.setCenter(@userLocation)
updateBoundsWithPolygons: ()->
for polygon in @polygons
polygon_points = polygon.serviceObject.latLngs.getArray()[0].getArray()
for point in polygon_points
@boundsObject.extend point
updateBoundsWithCircles: ()->
for circle in @circles
@boundsObject.extend(circle.serviceObject.getBounds().getNorthEast())
@boundsObject.extend(circle.serviceObject.getBounds().getSouthWest())
extendMapBounds: ()->
for bound in @map_options.bounds
#create points from bounds provided
@boundsObject.extend @createLatLng(bound.lat, bound.lng)
adaptMapToBounds:()->
#if autozoom is false, take user info into account
if !@map_options.auto_zoom
map_center = @boundsObject.getCenter()
@map_options.center_latitude = map_center.lat()
@map_options.center_longitude = map_center.lng()
@serviceObject.setCenter(map_center)
else
@fitBounds()

View File

@@ -1,145 +0,0 @@
#######################################################################################################
############################################## Map Quest #############################################
#######################################################################################################
# http://developer.mapquest.com/web/documentation/sdk/javascript/v7.0/api/MQA.Poi.html
class @Gmaps4RailsMapquest extends Gmaps4Rails
constructor: ->
super
#Map settings
@map_options = {type: "map"} #map type (map, sat, hyb)
@markers_conf = {}
@mergeWithDefault "markers_conf"
@mergeWithDefault "map_options"
#////////////////////////////////////////////////////
#/////////////// Basic Objects //////////////
#////////////////////////////////////////////////////
createPoint: (lat, lng) ->
return new MQA.Poi({lat: lat, lng: lng})
createLatLng: (lat, lng) ->
return {lat: lat, lng: lng}
createLatLngBounds: ->
createMap: ->
map = new MQA.TileMap( #// Constructs an instance of MQA.TileMap
document.getElementById(@map_options.id), #//the id of the element on the page you want the map to be added into
@map_options.zoom, #//intial zoom level of the map
{lat: @map_options.center_latitude, lng: @map_options.center_longitude},
@map_options.type) #//map type (map, sat, hyb)
MQA.withModule('zoomcontrol3', (->
map.addControl(
new MQA.LargeZoomControl3(),
new MQA.MapCornerPlacement(MQA.MapCorner.TOP_LEFT)
)
))
return map
createMarkerImage: (markerPicture, markerSize, origin, anchor, scaledSize) ->
#////////////////////////////////////////////////////
#////////////////////// Markers /////////////////////
#////////////////////////////////////////////////////
createMarker: (args)->
marker = new MQA.Poi( {lat: args.Lat, lng: args.Lng} )
if args.marker_picture != ""
icon = new MQA.Icon(args.marker_picture, args.marker_height, args.marker_width)
marker.setIcon(icon)
if args.marker_anchor != null
marker.setBias({x: args.marker_anchor[0], y: args.marker_anchor[1]})
if args.shadow_picture != ""
icon = new MQA.Icon(args.shadow_picture, args.shadow_height, args.shadow_width)
marker.setShadow(icon)
if args.shadow_anchor != null
marker.setShadowOffset({x: args.shadow_anchor[0], y: args.shadow_anchor[1]})
@addToMap marker
return marker
#// clear markers
clearMarkers: ->
for marker in markers
@clearMarker marker
#//show and hide markers
showMarkers: ->
for marker in markers
@showMarker marker
hideMarkers: ->
for marker in markers
@hideMarker marker
clearMarker: (marker) ->
@removeFromMap(marker.serviceObject)
showMarker: (marker) ->
#// marker.serviceObject
hideMarker: (marker) ->
#// marker.serviceObject
extendBoundsWithMarkers: ->
if @markers.length >=2
@boundsObject = new MQA.RectLL(@markers[0].serviceObject.latLng, @markers[1].serviceObject.latLng)
for marker in @markers
@boundsObject.extend marker.serviceObject.latLng
#////////////////////////////////////////////////////
#/////////////////// Clusterer //////////////////////
#////////////////////////////////////////////////////
createClusterer: (markers_array) ->
clearClusterer: ->
#//creates clusters
clusterize: ->
#////////////////////////////////////////////////////
#/////////////////// INFO WINDOW ////////////////////
#////////////////////////////////////////////////////
#// creates infowindows
createInfoWindow: (marker_container) ->
marker_container.serviceObject.setInfoTitleHTML(marker_container.description)
#//TODO: how to disable the mouseover display when using setInfoContentHTML?
#//marker_container.serviceObject.setInfoContentHTML(marker_container.description);
#////////////////////////////////////////////////////
#/////////////////// Other methods //////////////////
#////////////////////////////////////////////////////
fitBounds: ->
@serviceObject.zoomToRect @boundsObject if @markers.length >=2
@serviceObject.setCenter @markers[0].serviceObject.latLng if @markers.length == 1
centerMapOnUser: ->
@serviceObject.setCenter @userLocation
addToMap: (object) ->
@serviceObject.addShape object
removeFromMap: (object)->
@serviceObject.removeShape object
updateBoundsWithPolylines: ()->
updateBoundsWithPolygons: ()->
updateBoundsWithCircles: ()->
extendMapBounds :->
adaptMapToBounds: ->
@fitBounds()

View File

@@ -1,261 +0,0 @@
#######################################################################################################
############################################## Open Layers ##########################################
#######################################################################################################
#// http://wiki.openstreetmap.org/wiki/OpenLayers
#// http://openlayers.org/dev/examples
#//http://docs.openlayers.org/contents.html
class @Gmaps4RailsOpenlayers extends Gmaps4Rails
constructor: ->
super
@map_options = {}
@mergeWithDefault "map_options"
@markers_conf = {}
@mergeWithDefault "markers_conf"
@openMarkers = null
@markersLayer = null
@markersControl = null
@polylinesLayer = null
#////////////////////////////////////////////////////
#/////////////// Basic Objects ////////////////////
#////////////////////////////////////////////////////
createPoint: (lat, lng)->
createLatLng: (lat, lng)->
return new OpenLayers.LonLat(lng, lat).transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")) # transform from WGS 1984 to Spherical Mercator Projection
createAnchor: (offset)->
return null if offset == null
return new OpenLayers.Pixel(offset[0], offset[1])
createSize: (width, height)->
return new OpenLayers.Size(width, height)
createLatLngBounds: ->
return new OpenLayers.Bounds()
createMap: ->
#//todo add customization: kind of map and other map options
map = new OpenLayers.Map(@map_options.id)
map.addLayer(new OpenLayers.Layer.OSM())
map.setCenter(@createLatLng(@map_options.center_latitude, @map_options.center_longitude), #// Center of the map
@map_options.zoom) #// Zoom level
return map
#////////////////////////////////////////////////////
#////////////////////// Markers /////////////////////
#////////////////////////////////////////////////////
#//http://openlayers.org/dev/examples/marker-shadow.html
createMarker: (args) ->
style_mark = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default'])
style_mark.fillOpacity = 1
#//creating markers' dedicated layer
if (@markersLayer == null)
@markersLayer = new OpenLayers.Layer.Vector("Markers", null)
@serviceObject.addLayer(@markersLayer)
#//TODO move?
@markersLayer.events.register("featureselected", @markersLayer, @onFeatureSelect)
@markersLayer.events.register("featureunselected", @markersLayer, @onFeatureUnselect)
@markersControl = new OpenLayers.Control.SelectFeature(@markersLayer)
@serviceObject.addControl(@markersControl)
@markersControl.activate()
#//showing default pic if none available
if args.marker_picture == ""
#style_mark.graphicWidth = 24
style_mark.graphicHeight = 30
style_mark.externalGraphic = "http://openlayers.org/dev/img/marker-blue.png"
#//creating custom pic
else
style_mark.graphicWidth = args.marker_width
style_mark.graphicHeight = args.marker_height
style_mark.externalGraphic = args.marker_picture
#//adding anchor if any
if args.marker_anchor != null
style_mark.graphicXOffset = args.marker_anchor[0]
style_mark.graphicYOffset = args.marker_anchor[1]
#//adding shadow if any
if args.shadow_picture != ""
style_mark.backgroundGraphic = args.shadow_picture
style_mark.backgroundWidth = args.shadow_width
style_mark.backgroundHeight = args.shadow_height
#//adding shadow's anchor if any
if args.shadow_anchor != null
style_mark.backgroundXOffset = args.shadow_anchor[0]
style_mark.backgroundYOffset = args.shadow_anchor[1]
style_mark.graphicTitle = args.marker_title
marker = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(args.Lng, args.Lat),
null,
style_mark)
#//changing coordinates so that it actually appears on the map!
marker.geometry.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"))
#//adding layer to the map
@markersLayer.addFeatures([marker])
return marker
#//clear markers
clearMarkers: ->
@clearMarkersLayerIfExists()
@markersLayer = null
@boundsObject = new OpenLayers.Bounds()
clearMarkersLayerIfExists: ->
@serviceObject.removeLayer(@markersLayer) if @markersLayer != null and @serviceObject.getLayer(@markersLayer.id) != null
extendBoundsWithMarkers: ->
console.log "here"
for marker in @markers
@boundsObject.extend(@createLatLng(marker.lat,marker.lng))
#////////////////////////////////////////////////////
#/////////////////// Clusterer //////////////////////
#////////////////////////////////////////////////////
#//too ugly to be considered valid :(
createClusterer: (markers_array)->
options =
pointRadius: "${radius}"
fillColor: "#ffcc66"
fillOpacity: 0.8
strokeColor: "#cc6633"
strokeWidth: "${width}"
strokeOpacity: 0.8
funcs =
context:
width: (feature) ->
return (feature.cluster) ? 2 : 1
radius: (feature) ->
pix = 2
pix = Math.min(feature.attributes.count, 7) + 2 if feature.cluster
return pix
style = new OpenLayers.Style options, funcs
strategy = new OpenLayers.Strategy.Cluster()
clusters = new OpenLayers.Layer.Vector "Clusters",
strategies: [strategy]
styleMap: new OpenLayers.StyleMap
"default": style
"select":
fillColor: "#8aeeef"
strokeColor: "#32a8a9"
@clearMarkersLayerIfExists()
@serviceObject.addLayer(clusters)
clusters.addFeatures(markers_array)
return clusters
clusterize: ->
if @markers_conf.do_clustering == true
#//first clear the existing clusterer if any
if @markerClusterer != null
@clearClusterer()
markers_array = new Array
for marker in @markers
markers_array.push(marker.serviceObject)
@markerClusterer = @createClusterer markers_array
clearClusterer: ->
@serviceObject.removeLayer @markerClusterer
#////////////////////////////////////////////////////
#/////////////////// INFO WINDOW ////////////////////
#////////////////////////////////////////////////////
#// creates infowindows
createInfoWindow: (marker_container) ->
marker_container.serviceObject.infoWindow = marker_container.description if marker_container.description?
onPopupClose: (evt) ->
#// 'this' is the popup.
@markersControl.unselect @feature
onFeatureSelect: (evt) ->
feature = evt.feature
popup = new OpenLayers.Popup.FramedCloud("featurePopup",
feature.geometry.getBounds().getCenterLonLat(),
new OpenLayers.Size(300,200),
feature.infoWindow,
null, true, @onPopupClose)
feature.popup = popup
popup.feature = feature
@map.addPopup popup
onFeatureUnselect: (evt) ->
feature = evt.feature
if feature.popup
#//popup.feature = null;
@map.removePopup feature.popup
feature.popup.destroy()
feature.popup = null
#////////////////////////////////////////////////////
#/////////////////// POLYLINES //////////////////////
#////////////////////////////////////////////////////
create_polyline : (polyline) ->
if(@polylinesLayer == null)
@polylinesLayer = new OpenLayers.Layer.Vector("Polylines", null)
@serviceObject.addLayer(@polylinesLayer)
@polylinesLayer.events.register("featureselected", @polylinesLayer, @onFeatureSelect)
@polylinesLayer.events.register("featureunselected", @polylinesLayer, @onFeatureUnselect)
@polylinesControl = new OpenLayers.Control.DrawFeature(@polylinesLayer, OpenLayers.Handler.Path)
@serviceObject.addControl(@polylinesControl)
polyline_coordinates = []
for element in polyline
#by convention, a single polyline could be customized in the first array or it uses default values
if element == polyline[0]
strokeColor = element.strokeColor || @polylines_conf.strokeColor
strokeOpacity = element.strokeOpacity || @polylines_conf.strokeOpacity
strokeWeight = element.strokeWeight || @polylines_conf.strokeWeight
clickable = element.clickable || @polylines_conf.clickable
zIndex = element.zIndex || @polylines_conf.zIndex
#add latlng if positions provided
if element.lat? && element.lng?
latlng = new OpenLayers.Geometry.Point(element.lng, element.lat)
polyline_coordinates.push(latlng)
line_points = new OpenLayers.Geometry.LineString(polyline_coordinates);
line_style = { strokeColor: strokeColor, strokeOpacity: strokeOpacity, strokeWidth: strokeWeight };
polyline = new OpenLayers.Feature.Vector(line_points, null, line_style);
polyline.geometry.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"))
@polylinesLayer.addFeatures([polyline])
return polyline
updateBoundsWithPolylines: ()->
updateBoundsWithPolygons: ()->
updateBoundsWithCircles: ()->
# #////////////////////////////////////////////////////
# #/////////////////// Other methods //////////////////
# #////////////////////////////////////////////////////
fitBounds: ->
@serviceObject.zoomToExtent(@boundsObject, true)
centerMapOnUser: ->
@serviceObject.setCenter @userLocation
extendMapBounds :->
adaptMapToBounds: ->
@fitBounds()

View File

@@ -1,4 +0,0 @@
/*! Backstretch - v2.0.4 - 2013-06-19
* http://srobbin.com/jquery-plugins/backstretch/
* Copyright (c) 2013 Scott Robbin; Licensed MIT */
(function(a,d,p){a.fn.backstretch=function(c,b){(c===p||0===c.length)&&a.error("No images were supplied for Backstretch");0===a(d).scrollTop()&&d.scrollTo(0,0);return this.each(function(){var d=a(this),g=d.data("backstretch");if(g){if("string"==typeof c&&"function"==typeof g[c]){g[c](b);return}b=a.extend(g.options,b);g.destroy(!0)}g=new q(this,c,b);d.data("backstretch",g)})};a.backstretch=function(c,b){return a("body").backstretch(c,b).data("backstretch")};a.expr[":"].backstretch=function(c){return a(c).data("backstretch")!==p};a.fn.backstretch.defaults={centeredX:!0,centeredY:!0,duration:5E3,fade:0};var r={left:0,top:0,overflow:"hidden",margin:0,padding:0,height:"100%",width:"100%",zIndex:-999999},s={position:"absolute",display:"none",margin:0,padding:0,border:"none",width:"auto",height:"auto",maxHeight:"none",maxWidth:"none",zIndex:-999999},q=function(c,b,e){this.options=a.extend({},a.fn.backstretch.defaults,e||{});this.images=a.isArray(b)?b:[b];a.each(this.images,function(){a("<img />")[0].src=this});this.isBody=c===document.body;this.$container=a(c);this.$root=this.isBody?l?a(d):a(document):this.$container;c=this.$container.children(".backstretch").first();this.$wrap=c.length?c:a('<div class="backstretch"></div>').css(r).appendTo(this.$container);this.isBody||(c=this.$container.css("position"),b=this.$container.css("zIndex"),this.$container.css({position:"static"===c?"relative":c,zIndex:"auto"===b?0:b,background:"none"}),this.$wrap.css({zIndex:-999998}));this.$wrap.css({position:this.isBody&&l?"fixed":"absolute"});this.index=0;this.show(this.index);a(d).on("resize.backstretch",a.proxy(this.resize,this)).on("orientationchange.backstretch",a.proxy(function(){this.isBody&&0===d.pageYOffset&&(d.scrollTo(0,1),this.resize())},this))};q.prototype={resize:function(){try{var a={left:0,top:0},b=this.isBody?this.$root.width():this.$root.innerWidth(),e=b,g=this.isBody?d.innerHeight?d.innerHeight:this.$root.height():this.$root.innerHeight(),j=e/this.$img.data("ratio"),f;j>=g?(f=(j-g)/2,this.options.centeredY&&(a.top="-"+f+"px")):(j=g,e=j*this.$img.data("ratio"),f=(e-b)/2,this.options.centeredX&&(a.left="-"+f+"px"));this.$wrap.css({width:b,height:g}).find("img:not(.deleteable)").css({width:e,height:j}).css(a)}catch(h){}return this},show:function(c){if(!(Math.abs(c)>this.images.length-1)){var b=this,e=b.$wrap.find("img").addClass("deleteable"),d={relatedTarget:b.$container[0]};b.$container.trigger(a.Event("backstretch.before",d),[b,c]);this.index=c;clearInterval(b.interval);b.$img=a("<img />").css(s).bind("load",function(f){var h=this.width||a(f.target).width();f=this.height||a(f.target).height();a(this).data("ratio",h/f);a(this).fadeIn(b.options.speed||b.options.fade,function(){e.remove();b.paused||b.cycle();a(["after","show"]).each(function(){b.$container.trigger(a.Event("backstretch."+this,d),[b,c])})});b.resize()}).appendTo(b.$wrap);b.$img.attr("src",b.images[c]);return b}},next:function(){return this.show(this.index<this.images.length-1?this.index+1:0)},prev:function(){return this.show(0===this.index?this.images.length-1:this.index-1)},pause:function(){this.paused=!0;return this},resume:function(){this.paused=!1;this.next();return this},cycle:function(){1<this.images.length&&(clearInterval(this.interval),this.interval=setInterval(a.proxy(function(){this.paused||this.next()},this),this.options.duration));return this},destroy:function(c){a(d).off("resize.backstretch orientationchange.backstretch");clearInterval(this.interval);c||this.$wrap.remove();this.$container.removeData("backstretch")}};var l,f=navigator.userAgent,m=navigator.platform,e=f.match(/AppleWebKit\/([0-9]+)/),e=!!e&&e[1],h=f.match(/Fennec\/([0-9]+)/),h=!!h&&h[1],n=f.match(/Opera Mobi\/([0-9]+)/),t=!!n&&n[1],k=f.match(/MSIE ([0-9]+)/),k=!!k&&k[1];l=!((-1<m.indexOf("iPhone")||-1<m.indexOf("iPad")||-1<m.indexOf("iPod"))&&e&&534>e||d.operamini&&"[object OperaMini]"==={}.toString.call(d.operamini)||n&&7458>t||-1<f.indexOf("Android")&&e&&533>e||h&&6>h||"palmGetResource"in d&&e&&534>e||-1<f.indexOf("MeeGo")&&-1<f.indexOf("NokiaBrowser/8.5.0")||k&&6>=k)})(jQuery,window);

View File

@@ -1,62 +0,0 @@
//;(function (window, document, $) {
// alert($("#sidebarButton").html());
//}(this, document, jQuery));
//;(function (window, document, $) {
// // Set the negative margin on the top menu for slide-menu pages
// var $selector1 = $('#topMenu'),
// events = 'click.fndtn';
// if ($selector1.length > 0) $selector1.css("margin-top", $selector1.height() * -1);
//
// // Watch for clicks to show the sidebar
// var $selector2 = $('#sidebarButton');
// if ($selector2.length > 0) {
// $('#sidebarButton').on(events, function (e) {
// console.log("testing one two three");
// e.preventDefault();
// $('body').toggleClass('active');
// });
// }
// else {
// console.log("not supposed to be there");
// }
//
// // Watch for clicks to show the menu for slide-menu pages
// var $selector3 = $('#menuButton');
// if ($selector3.length > 0) {
// $('#menuButton').on(events, function (e) {
// e.preventDefault();
// $('body').toggleClass('active-menu');
// });
// }
//
// // // Adjust sidebars and sizes when resized
// // $(window).resize(function() {
// // // if (!navigator.userAgent.match(/Android/i)) $('body').removeClass('active');
// // var $selector4 = $('#topMenu');
// // if ($selector4.length > 0) $selector4.css("margin-top", $selector4.height() * -1);
// // });
//
// // Switch panels for the paneled nav on mobile
// var $selector5 = $('#switchPanels');
// if ($selector5.length > 0) {
// $('#switchPanels dd').on(events, function (e) {
// e.preventDefault();
// var switchToPanel = $(this).children('a').attr('href'),
// switchToIndex = $(switchToPanel).index();
// $(this).toggleClass('active').siblings().removeClass('active');
// $(switchToPanel).parent().css("left", (switchToIndex * (-100) + '%'));
// });
// }
//
// $('#nav li a').on(events, function (e) {
// alert("test");
// e.preventDefault();
// var href = $(this).attr('href'),
// $target = $(href);
// $('html, body').animate({scrollTop : $target.offset().top}, 300);
// });
//}(this, document, jQuery));

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +0,0 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

View File

@@ -9,7 +9,5 @@
//= require store/spree_core
//= require store/spree_auth
//= require store/spree_promo
//= require angular
//= require angular-resource
//= require_tree .

View File

@@ -1,8 +0,0 @@
$(document).ready ->
$('#cart_adjustments').hide()
$('th.cart-adjustment-header').html('<a href="#">Distribution...</a>')
$('th.cart-adjustment-header a').click ->
$('#cart_adjustments').toggle()
$('th.cart-adjustment-header a').html('Distribution')
false

View File

@@ -1,20 +0,0 @@
'use strict'
angular.module('store', ['ngResource']).
controller('CartCtrl', ['$scope', '$window', 'CartFactory', ($scope, $window, CartFactory) ->
$scope.state = 'Empty'
$scope.loadCart = (cart_id) ->
if cart_id?
CartFactory.load cart_id, (cart) ->
$scope.cart = cart
if $scope.cart?.orders?.length > 0
$scope.state = "There's something there...."
$scope.addVariant = (variant, quantity) ->
])
.config(['$httpProvider', ($httpProvider) ->
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
])

View File

@@ -1,11 +0,0 @@
'use strict'
angular.module('store').
factory('CartFactory', ['$resource', '$window', '$http', ($resource, $window, $http) ->
Cart = $resource '/open_food_network/cart/:cart_id.json', {},
{ 'show': { method: 'GET'} }
load: (id, callback) ->
Cart.show {cart_id: id}, (cart) ->
callback(cart)
])

View File

@@ -1,47 +0,0 @@
/**
* Update the price on the product details page in real time when the variant or the quantity are changed.
**/
$(document).ready(function() {
// Product page with variant choice
$("#product-variants input[type='radio']").change(products_update_price_with_variant);
$("#quantity").change(products_update_price_with_variant);
$("#quantity").change();
// Product page with master price only
$(".add-to-cart input.title:not(#quantity):not(.max_quantity)").change(products_update_price_without_variant).change();
// Product page other
$("#distributor_id").change(function() {
var distributor_html = distributors[$(this).val()];
if(!distributor_html) {
distributor_html = 'When you select a distributor for your order, their address and pickup times will be displayed here.';
}
$("#product-distributor-details .distributor-details").html(distributor_html);
});
});
function products_update_price_with_variant() {
var variant_price = $("#product-variants input[type='radio']:checked").parent().find("span.price").html().trim();
variant_price = variant_price.substr(2, variant_price.length-3);
var quantity = $("#quantity").val();
$("#product-price span.price").html("$"+(parseFloat(variant_price) * parseInt(quantity)).toFixed(2));
}
function products_update_price_without_variant() {
var master_price = $("#product-price span.price").data('master-price');
if(master_price == null) {
// Store off the master price
master_price = $("#product-price span.price").html();
master_price = master_price.substring(1);
$("#product-price span.price").data('master-price', master_price);
}
var quantity = $(this).val();
$("#product-price span.price").html("$"+(parseFloat(master_price)*parseInt(quantity)).toFixed(2));
}

View File

@@ -1,4 +0,0 @@
$(document).ready ->
$("#order_order_cycle_id").change -> $("#order_cycle_select").submit()
$("#reset_order_cycle").click -> return false unless confirm "Changing your collection date will clear your cart."
$(".shop-distributor.empties-cart").click -> return false unless confirm "Changing your location will clear your cart."

View File

@@ -1,4 +0,0 @@
%ng-include{src: "'partials/enterprise_header.html'"}
%ng-include{src: "'partials/enterprise_details.html'"}
%ng-include{src: "'partials/hub_actions.html'"}
%ng-include{src: "'partials/close.html'"}

View File

@@ -1,13 +1,13 @@
.highlight{"ng-class" => "{'has_shopfront' : enterprise.has_shopfront}"}
.highlight{"ng-class" => "{'is_distributor' : enterprise.is_distributor}"}
.highlight-top.row
.small-12.medium-7.large-8.columns
%h3{"ng-if" => "enterprise.has_shopfront"}
%h3{"ng-if" => "enterprise.is_distributor"}
%a{"bo-href" => "enterprise.path", "ofn-empties-cart" => "enterprise", bindonce: true}
%i{"ng-class" => "enterprise.icon_font"}
%span {{ enterprise.name }}
%h3{"ng-if" => "!enterprise.has_shopfront", "ng-class" => "{'is_producer' : enterprise.is_primary_producer}"}
%h3{"ng-if" => "!enterprise.is_distributor", "ng-class" => "{'is_producer' : enterprise.is_primary_producer}"}
%i{"ng-class" => "enterprise.icon_font"}
%span {{ enterprise.name }}
.small-12.medium-5.large-4.columns.text-right.small-only-text-left
%p {{ [enterprise.address.city, enterprise.address.state_name] | printArray}}
%img.hero-img{"ng-src" => "{{enterprise.promo_image}}"}
%img.hero-img{"ng-src" => "{{enterprise.promo_image}}"}

View File

@@ -1,4 +1,4 @@
.row.pad-top{bindonce: true, "ng-if" => "enterprise.hubs.length > 0 && enterprise.has_shopfront"}
.row.pad-top{bindonce: true, "ng-if" => "enterprise.hubs.length > 0 && enterprise.is_distributor"}
.cta-container.small-12.columns
%label
Shop for

View File

@@ -1,4 +1,4 @@
.row.pad-top{bindonce: true, ng: { if: 'enterprise.has_shopfront' } }
.row.pad-top{bindonce: true, ng: { if: 'enterprise.is_distributor' } }
.cta-container.small-12.columns
.row
.small-4.columns

View File

@@ -1,3 +0,0 @@
%ng-include{src: "'partials/enterprise_header.html'"}
%ng-include{src: "'partials/enterprise_details.html'"}
%ng-include{src: "'partials/close.html'"}

View File

@@ -1,26 +1,27 @@
.container#registration-details{bindonce: true}
.header
%h2 Let's Get Started
%h5{ bo: { if: "enterprise.type != 'single'" } } Woot! First we need to know what sort of enterprise you are:
%h5{ bo: { if: "enterprise.type == 'single'" } } Woot! First we need to know the name of your farm:
%h5{ bo: { if: "enterprise.sells != 'own'" } } Woot! First we need to know what sort of enterprise you are:
%h5{ bo: { if: "enterprise.sells == 'own'" } } Woot! First we need to know the name of your farm:
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'details', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('address',details)" } }
.row
.small-12.columns.field
%label{ for: 'enterprise_name', bo: { if: "enterprise.type != 'single'" } } Enterprise Name:
%label{ for: 'enterprise_name', bo: { if: "enterprise.type == 'single'" } } Farm Name:
%label{ for: 'enterprise_name', bo: { if: "enterprise.sells != 'own'" } } Enterprise Name:
%label{ for: 'enterprise_name', bo: { if: "enterprise.sells == 'own'" } } Farm Name:
%input.chunky.small-12.columns{ id: 'enterprise_name', name: 'name', placeholder: "eg. Charlie's Awesome Farm", required: true, ng: { model: 'enterprise.name' } }
%span.error.small-12.columns{ ng: { show: "details.name.$error.required && submitted" } }
You need to enter a name for your enterprise!
.row#enterprise-types{ 'data-equalizer' => true, bo: { if: "enterprise.type != 'single'" } }
.row#enterprise-types{ 'data-equalizer' => true, bo: { if: "enterprise.sells != 'own'" } }
.small-12.columns.field
.row
.small-12.columns
%label Choose one:
.row
-# TODO redesign this to refelct the extra options available.
.small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
%a.panel#producer-panel{ href: "#", ng: { click: "enterprise.is_distributor = false; enterprise.is_primary_producer = true", class: "{selected: (!enterprise.is_distributor && enterprise.is_primary_producer)}" } }
%a.panel#producer-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = true", class: "{selected: (!enterprise.is_distributor && enterprise.is_primary_producer)}" } }
.left
/ %render-svg{ path: "/assets/map-icon-producer.svg" }
%h4 I'm A Producer