mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge branch 'migrate_ent_types' into bugfix
Conflicts: app/models/spree/ability_decorator.rb
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -1,6 +0,0 @@
|
||||
Darkswarm.filter 'filterProducers', (hubsFilter)->
|
||||
(producers, text) ->
|
||||
producers ||= []
|
||||
text ?= ""
|
||||
hubsFilter(producers, text)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,7 +0,0 @@
|
||||
Darkswarm.filter 'showProfiles', ()->
|
||||
(enterprises, show_profiles) ->
|
||||
enterprises ||= []
|
||||
show_profiles ?= true
|
||||
|
||||
enterprises.filter (enterprise)=>
|
||||
show_profiles or enterprise.has_shopfront
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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'])
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(); });
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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);
|
||||
@@ -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
@@ -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/
|
||||
@@ -9,7 +9,5 @@
|
||||
//= require store/spree_core
|
||||
//= require store/spree_auth
|
||||
//= require store/spree_promo
|
||||
//= require angular
|
||||
//= require angular-resource
|
||||
|
||||
//= require_tree .
|
||||
|
||||
@@ -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
|
||||
@@ -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')
|
||||
])
|
||||
@@ -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)
|
||||
])
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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."
|
||||
@@ -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'"}
|
||||
@@ -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}}"}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
%ng-include{src: "'partials/enterprise_header.html'"}
|
||||
%ng-include{src: "'partials/enterprise_details.html'"}
|
||||
%ng-include{src: "'partials/close.html'"}
|
||||
@@ -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
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
span
|
||||
text-decoration: underline
|
||||
|
||||
&.has_shopfront, &.has_shopfront i.ofn-i_059-producer, &.has_shopfront i.ofn-i_060-producer-reversed
|
||||
&.is_distributor, &.is_distributor i.ofn-i_059-producer, &.is_distributor i.ofn-i_060-producer-reversed
|
||||
color: $clr-brick
|
||||
&:hover, &:active, &:focus
|
||||
color: $clr-brick-bright
|
||||
|
||||
@@ -74,8 +74,10 @@ button.success, .button.success
|
||||
|
||||
.profile-checkbox
|
||||
display: inline-block
|
||||
input[type="checkbox"] + label
|
||||
label
|
||||
margin: 0 0.2rem
|
||||
float: right
|
||||
|
||||
|
||||
// Responsive
|
||||
@media screen and (min-width: 768px)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
// Place all the styles related to the distributors controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
||||
@@ -1,3 +0,0 @@
|
||||
// Place all the styles related to the groups controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
||||
@@ -1,3 +0,0 @@
|
||||
// Place all the styles related to the Shop::Checkout controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
||||
@@ -1,381 +0,0 @@
|
||||
@import "screen";
|
||||
@import "compass/css3/border-radius";
|
||||
|
||||
/* General purpose styles */
|
||||
|
||||
a:hover {
|
||||
color: lighten($link_text_color, 20) !important;
|
||||
}
|
||||
|
||||
/* Cleared div for clearing previous floating elements */
|
||||
div.cleared {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
p.hint {
|
||||
margin: 0 0 0.5em 0;
|
||||
padding: 0;
|
||||
color: #6a6a6a;
|
||||
}
|
||||
|
||||
table {
|
||||
tbody, tfoot {
|
||||
tr {
|
||||
&.alt, &.odd {
|
||||
background-color: lighten($link_text_color, 75) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Style current distributor in main nav bar */
|
||||
#header {
|
||||
margin-bottom: 40px;
|
||||
|
||||
#logo {
|
||||
position: relative;
|
||||
margin-top: 40px;
|
||||
padding-top: 10px;
|
||||
|
||||
h1 {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.change-location {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
right: -104px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nav #main-nav-bar {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 10px;
|
||||
width: 100%;
|
||||
|
||||
#link-to-cart {
|
||||
position: relative;
|
||||
top: 40px;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
li {
|
||||
&#current-distribution {
|
||||
float: right;
|
||||
clear: right;
|
||||
margin: 0.5em 5px 0 0;
|
||||
|
||||
a {
|
||||
font-size: 12px;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nav#top-nav-bar {
|
||||
position: relative;
|
||||
z-index: 999;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
|
||||
/* Based on Spree's nav#taxonomies style. Copied instead of
|
||||
* extended with SASS because SASS does not allow extending
|
||||
* nested selectors.
|
||||
*/
|
||||
nav#filters {
|
||||
.filter_name {
|
||||
text-transform: uppercase;
|
||||
border-bottom: 1px solid lighten($body_text_color, 60);
|
||||
margin-bottom: 5px;
|
||||
font-size: $main_navigation_header_font_size;
|
||||
}
|
||||
|
||||
.filter_choices {
|
||||
padding-left: 20px;
|
||||
margin-bottom: 5px;
|
||||
list-style: disc outside;
|
||||
|
||||
li {
|
||||
a {
|
||||
font-size: $main_navigation_font_size;
|
||||
}
|
||||
span.inactive {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input[type=submit] {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Distributor and order cycle selection and display */
|
||||
#distribution-choice {
|
||||
margin-bottom: 2em;
|
||||
padding: 5px;
|
||||
border: 2px solid #ccc;
|
||||
@include border-radius(10px);
|
||||
}
|
||||
|
||||
#distribution-selection {
|
||||
overflow: auto;
|
||||
margin-bottom: 2em;
|
||||
padding: 20px;
|
||||
background-color: #f3f3f3;
|
||||
|
||||
.distributors {
|
||||
float: left;
|
||||
margin-right: 4em;
|
||||
|
||||
option.local {
|
||||
background-color: #cfc;
|
||||
}
|
||||
option.remote {
|
||||
background-color: #fcc;
|
||||
}
|
||||
}
|
||||
|
||||
.order-cycles {
|
||||
|
||||
select {
|
||||
padding: 10px;
|
||||
margin-top: 15px;
|
||||
border: 2px solid white;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
float: left;
|
||||
|
||||
tr.local {
|
||||
background-color: #cfc;
|
||||
}
|
||||
tr.remote {
|
||||
background-color: #fcc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.countdown-panel {
|
||||
background: url("../countdown.png") no-repeat left;
|
||||
min-height: 60px;
|
||||
min-width: 70px;
|
||||
padding-left: 77px;
|
||||
}
|
||||
|
||||
|
||||
/* Style the product source on the product details page in the
|
||||
* same manner as the product properties table above it.
|
||||
*/
|
||||
#product-source {
|
||||
@extend #product-properties;
|
||||
}
|
||||
#product-properties td, #product-source td {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
|
||||
/* Apply Spree's ul#products style to ul.product-listing. When viewing products
|
||||
* split by distributor, a separate product listing is displayed for local and
|
||||
* remote products, so the #products id is removed to avoid its duplication.
|
||||
*/
|
||||
ul.product-listing {
|
||||
&:after {
|
||||
content: " ";
|
||||
display: block;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
line-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
|
||||
&.info {
|
||||
height: 35px;
|
||||
margin-top: 5px;
|
||||
font-size: $product_list_name_font_size;
|
||||
color: $product_link_text_color;
|
||||
border-bottom: 1px solid lighten($body_text_color, 60);
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.product-image {
|
||||
border: 1px solid lighten($body_text_color, 60);
|
||||
padding: 5px;
|
||||
min-height: 110px;
|
||||
background-color: $product_background_color;
|
||||
|
||||
&:hover {
|
||||
border-color: $link_text_color;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.price {
|
||||
color: $link_text_color;
|
||||
font-size: $product_list_price_font_size;
|
||||
padding-top: 5px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Enterprise description */
|
||||
.enterprise-description {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
|
||||
/* Supplier page distributor listing */
|
||||
#supplier-distributors li a.inactive {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
|
||||
/* Highlight local products in distributor-split product listings */
|
||||
#products-local ul {
|
||||
margin-bottom: 1em;
|
||||
padding: 10px;
|
||||
@include border-radius(10px);
|
||||
background-color: #def;
|
||||
}
|
||||
|
||||
|
||||
/* Distributor details on product details page */
|
||||
fieldset#product-distributor-details {
|
||||
float: right;
|
||||
margin-top: 0;
|
||||
width: 250px;
|
||||
@extend #shipping;
|
||||
}
|
||||
|
||||
#product-variants {
|
||||
float: none;
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Add to cart form on product details page */
|
||||
#cart-form {
|
||||
.error-distributor {
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
color: #f00;
|
||||
|
||||
a {
|
||||
color: #f00;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.distributor-fixed {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* View cart form */
|
||||
#subtotal {
|
||||
width: 100%;
|
||||
}
|
||||
.links {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
#empty-cart {
|
||||
float: left;
|
||||
margin-top: 15px !important;
|
||||
|
||||
p {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Checkout address page */
|
||||
#checkout .alternative-available-distributors {
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
|
||||
/* Delivery fees table on checkout page */
|
||||
#delivery-fees {
|
||||
clear: both;
|
||||
padding-top: 6em;
|
||||
|
||||
table#delivery {
|
||||
width: 100%;
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
td.item-shipping-cost, td.item-shipping-method {
|
||||
text-align: center;
|
||||
}
|
||||
td.item-shipping-cost {
|
||||
@extend span.price;
|
||||
@extend span.price.selling;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subtotal {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
margin-top: 15px;
|
||||
|
||||
span.order-total {
|
||||
@extend span.price;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Alert for EFT Payment during checkout process */
|
||||
div#eft-payment-alert {
|
||||
border: 2px solid red;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
/* Large 'Save and Continue/Process My Order' button under Order Summary on the checkout pages */
|
||||
#add_new_save_checkout_button {
|
||||
display: none;
|
||||
margin-top: 30px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #d9d9db;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
color: #6A6A6A;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* Distributor details */
|
||||
.distributor-details .next-collection-at {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #de790c;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*--------------------------------------*/
|
||||
/* Colors
|
||||
/*--------------------------------------*/
|
||||
$c_green: #8dba53 !default; /* Spree green */
|
||||
$c_red: #e45353 !default; /* Error red */
|
||||
|
||||
$layout_background_color: #FFFFFF !default;
|
||||
$title_text_color: #404042 !default;
|
||||
$body_text_color: #404042 !default;
|
||||
$link_text_color: #00ADEE !default;
|
||||
|
||||
$product_background_color: #FFFFFF !default;
|
||||
$product_title_text_color: #404042 !default;
|
||||
$product_body_text_color: #404042 !default;
|
||||
$product_link_text_color: #BBBBBB !default;
|
||||
|
||||
/*--------------------------------------*/
|
||||
/* Fonts import from remote
|
||||
/*--------------------------------------*/
|
||||
@import url(//fonts.googleapis.com/css?family=Ubuntu:400,700,400italic,700italic|&subset=latin,cyrillic,greek,greek-ext,latin-ext,cyrillic-ext);
|
||||
|
||||
/*--------------------------------------*/
|
||||
/* Font families
|
||||
/*--------------------------------------*/
|
||||
$ff_base: 'Ubuntu', sans-serif !default;
|
||||
|
||||
/*--------------------------------------
|
||||
| Font sizes
|
||||
|--------------------------------------
|
||||
|- Navigation
|
||||
| */
|
||||
$header_navigation_font_size: 14px !default;
|
||||
$horizontal_navigation_font_size: 16px !default;
|
||||
$main_navigation_header_font_size: 14px !default;
|
||||
$main_navigation_font_size: 12px !default;
|
||||
/*|------------------------------------
|
||||
|- Product Listing
|
||||
| */
|
||||
$product_list_name_font_size: 12px !default;
|
||||
$product_list_price_font_size: 16px !default;
|
||||
$product_list_header_font_size: 20px !default;
|
||||
$product_list_search_font_size: 14px !default;
|
||||
/*|------------------------------------
|
||||
|- Product Details
|
||||
| */
|
||||
$product_detail_name_font_size: 24px !default;
|
||||
$product_detail_description_font_size: 12px !default;
|
||||
$product_detail_price_font_size: 20px !default;
|
||||
$product_detail_title_font_size: 14px !default;
|
||||
/*|------------------------------------
|
||||
|- Basic
|
||||
| */
|
||||
$heading_font_size: 24px !default;
|
||||
$sub_heading_font_size: 14px !default;
|
||||
$button_font_size: 12px !default;
|
||||
$input_box_font_size: 13px !default;
|
||||
$base_font_size: 12px !default;
|
||||
$border_color: lighten($body_text_color, 60) !default;
|
||||
$default_border: 1px solid $border_color !default;
|
||||
$button_border_color: rgba(0, 138, 189, .75) !default;
|
||||
$table_head_color: lighten($body_text_color, 60) !default;
|
||||
|
||||
|
||||
@import "./store/variables_changes.css.scss";
|
||||
@@ -1 +0,0 @@
|
||||
$link_text_color: #006066;
|
||||
@@ -3,11 +3,11 @@ module Admin
|
||||
before_filter :load_enterprise_set, :only => :index
|
||||
before_filter :load_countries, :except => :index
|
||||
before_filter :load_methods_and_fees, :only => [:new, :edit, :update, :create]
|
||||
before_filter :check_type, only: :update
|
||||
before_filter :check_bulk_type, only: :bulk_update
|
||||
before_filter :check_can_change_sells, only: :update
|
||||
before_filter :check_can_change_bulk_sells, only: :bulk_update
|
||||
before_filter :override_owner, only: :create
|
||||
before_filter :check_owner, only: :update
|
||||
before_filter :check_bulk_owner, only: :bulk_update
|
||||
before_filter :check_can_change_owner, only: :update
|
||||
before_filter :check_can_change_bulk_owner, only: :bulk_update
|
||||
|
||||
helper 'spree/products'
|
||||
include OrderCyclesHelper
|
||||
@@ -50,7 +50,8 @@ module Admin
|
||||
end
|
||||
|
||||
def collection
|
||||
Enterprise.managed_by(spree_current_user).order('is_distributor DESC, is_primary_producer ASC, name')
|
||||
# TODO was ordered with is_distributor DESC as well, not sure why or how we want ot sort this now
|
||||
Enterprise.managed_by(spree_current_user).order('is_primary_producer ASC, name')
|
||||
end
|
||||
|
||||
def collection_actions
|
||||
@@ -63,29 +64,29 @@ module Admin
|
||||
@enterprise_fees = EnterpriseFee.managed_by(spree_current_user).for_enterprise(@enterprise).order(:fee_type, :name).all
|
||||
end
|
||||
|
||||
def check_bulk_type
|
||||
def check_can_change_bulk_sells
|
||||
unless spree_current_user.admin?
|
||||
params[:enterprise_set][:collection_attributes].each do |i, enterprise_params|
|
||||
enterprise_params.delete :type
|
||||
enterprise_params.delete :sells
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_type
|
||||
params[:enterprise].delete :type unless spree_current_user.admin?
|
||||
def check_can_change_sells
|
||||
params[:enterprise].delete :sells unless spree_current_user.admin?
|
||||
end
|
||||
|
||||
def override_owner
|
||||
params[:enterprise][:owner_id] = spree_current_user.id unless spree_current_user.admin?
|
||||
end
|
||||
|
||||
def check_owner
|
||||
def check_can_change_owner
|
||||
unless ( spree_current_user == @enterprise.owner ) || spree_current_user.admin?
|
||||
params[:enterprise].delete :owner_id
|
||||
end
|
||||
end
|
||||
|
||||
def check_bulk_owner
|
||||
def check_can_change_bulk_owner
|
||||
unless spree_current_user.admin?
|
||||
params[:enterprise_set][:collection_attributes].each do |i, enterprise_params|
|
||||
enterprise_params.delete :owner_id
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
Spree::Admin::OverviewController.class_eval do
|
||||
def index
|
||||
@enterprises = Enterprise.managed_by(spree_current_user).order('is_distributor DESC, is_primary_producer ASC, name')
|
||||
# TODO was sorted with is_distributor DESC as well, not sure why or how we want ot sort this now
|
||||
@enterprises = Enterprise.managed_by(spree_current_user).order('is_primary_producer ASC, name')
|
||||
@product_count = Spree::Product.active.managed_by(spree_current_user).count
|
||||
@order_cycle_count = OrderCycle.active.managed_by(spree_current_user).count
|
||||
end
|
||||
|
||||
@@ -594,10 +594,12 @@ Spree::Admin::ReportsController.class_eval do
|
||||
private
|
||||
|
||||
def load_data
|
||||
# Load distributors either owned by the user or selling their enterprises products.
|
||||
my_distributors = Enterprise.is_distributor.managed_by(spree_current_user)
|
||||
my_suppliers = Enterprise.is_primary_producer.managed_by(spree_current_user)
|
||||
distributors_of_my_products = Enterprise.with_distributed_products_outer.merge(Spree::Product.in_any_supplier(my_suppliers))
|
||||
@distributors = my_distributors | distributors_of_my_products
|
||||
# Load suppliers either owned by the user or supplying products their enterprises distribute.
|
||||
suppliers_of_products_I_distribute = my_distributors.map { |d| Spree::Product.in_distributor(d) }.flatten.map(&:supplier).uniq
|
||||
@suppliers = my_suppliers | suppliers_of_products_I_distribute
|
||||
@order_cycles = OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class Enterprise < ActiveRecord::Base
|
||||
TYPES = %w(full single profile)
|
||||
SELLS = %w(none own any)
|
||||
ENTERPRISE_SEARCH_RADIUS = 100
|
||||
self.inheritance_column = nil
|
||||
|
||||
@@ -46,7 +46,7 @@ class Enterprise < ActiveRecord::Base
|
||||
|
||||
|
||||
validates :name, presence: true
|
||||
validates :type, presence: true, inclusion: {in: TYPES}
|
||||
validates :sells, presence: true, inclusion: {in: SELLS}
|
||||
validates :address, presence: true, associated: true
|
||||
validates :email, presence: true
|
||||
validates_presence_of :owner
|
||||
@@ -60,7 +60,7 @@ class Enterprise < ActiveRecord::Base
|
||||
scope :by_name, order('name')
|
||||
scope :visible, where(:visible => true)
|
||||
scope :is_primary_producer, where(:is_primary_producer => true)
|
||||
scope :is_distributor, where(:is_distributor => true)
|
||||
scope :is_distributor, where('sells != ?', 'none')
|
||||
scope :supplying_variant_in, lambda { |variants| joins(:supplied_products => :variants_including_master).where('spree_variants.id IN (?)', variants).select('DISTINCT enterprises.*') }
|
||||
scope :with_supplied_active_products_on_hand, lambda {
|
||||
joins(:supplied_products)
|
||||
@@ -211,36 +211,30 @@ class Enterprise < ActiveRecord::Base
|
||||
Spree::Variant.joins(:product => :product_distributions).where('product_distributions.distributor_id=?', self.id)
|
||||
end
|
||||
|
||||
# Replaces currententerprse type field.
|
||||
def sells
|
||||
# Type: full - single - profile becomes Sells: all - own - none
|
||||
# Remove this return later.
|
||||
return "none" if !is_distributor || type == "profile"
|
||||
return "own" if type == "single" || suppliers == [self]
|
||||
"all"
|
||||
def is_distributor
|
||||
self.sells != "none"
|
||||
end
|
||||
|
||||
# Simplify enterprise categories for frontend logic and icons, and maybe other things.
|
||||
def enterprise_category
|
||||
def category
|
||||
# Make this crazy logic human readable so we can argue about it sanely.
|
||||
# This can be simplified later, it's like this for readablitlty during changes.
|
||||
category = is_primary_producer ? "producer_" : "non_producer_"
|
||||
category << "sell_" + sells
|
||||
cat = self.is_primary_producer ? "producer_" : "non_producer_"
|
||||
cat << "sells_" + self.sells
|
||||
|
||||
# Map backend cases to front end cases.
|
||||
case category
|
||||
when "producer_sell_all"
|
||||
"producer_hub" # Producer hub who sells own and others produce and supplies other hubs.
|
||||
when "producer_sell_own"
|
||||
"producer_shop" # Producer with shopfront and supplies other hubs.
|
||||
when "producer_sell_none"
|
||||
"producer" # Producer only supplies through others.
|
||||
when "non_producer_sell_all"
|
||||
"hub" # Hub selling others products in order cycles.
|
||||
when "non_producer_sell_own"
|
||||
"hub" # Wholesaler selling through own shopfront?
|
||||
when "non_producer_sell_none"
|
||||
"hub_profile" # Hub selling outside the system.
|
||||
case cat
|
||||
when "producer_sells_any"
|
||||
:producer_hub # Producer hub who sells own and others produce and supplies other hubs.
|
||||
when "producer_sells_own"
|
||||
:producer_shop # Producer with shopfront and supplies other hubs.
|
||||
when "producer_sells_none"
|
||||
:producer # Producer only supplies through others.
|
||||
when "non_producer_sells_any"
|
||||
:hub # Hub selling others products in order cycles.
|
||||
when "non_producer_sells_own"
|
||||
:hub # Wholesaler selling through own shopfront? Does this need a separate name? Should it exist?
|
||||
when "non_producer_sells_none"
|
||||
:hub_profile # Hub selling outside the system.
|
||||
end
|
||||
end
|
||||
|
||||
@@ -267,7 +261,7 @@ class Enterprise < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def strip_url(url)
|
||||
url.andand.sub /(https?:\/\/)?/, ''
|
||||
url.andand.sub(/(https?:\/\/)?/, '')
|
||||
end
|
||||
|
||||
def set_unused_address_fields
|
||||
|
||||
@@ -28,7 +28,7 @@ class AbilityDecorator
|
||||
|
||||
# Users can manage orders if they have a sells own/any enterprise.
|
||||
def can_manage_orders?(user)
|
||||
( user.enterprises.map(&:type) & %w(single full) ).any?
|
||||
( user.enterprises.map(&:sells) & %w(own any) ).any?
|
||||
end
|
||||
|
||||
def can_manage_relationships?(user)
|
||||
@@ -80,7 +80,7 @@ class AbilityDecorator
|
||||
can [:admin, :index, :read, :create, :edit], Spree::Classification
|
||||
|
||||
# Reports page
|
||||
can [:admin, :index, :customers, :bulk_coop, :orders_and_fulfillment, :products_and_inventory], :report
|
||||
can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory], :report
|
||||
end
|
||||
|
||||
def add_order_management_abilities(user)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
|
||||
attributes :name, :id, :is_primary_producer, :is_distributor, :payment_method_ids, :shipping_method_ids
|
||||
attributes :name, :id, :is_primary_producer, :is_distributor, :sells, :category, :payment_method_ids, :shipping_method_ids
|
||||
end
|
||||
|
||||
@@ -17,9 +17,6 @@ end
|
||||
class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
attributes :orders_close_at, :active
|
||||
|
||||
#TODO: Remove these later
|
||||
attributes :icon, :icon_font, :producer_icon_font, :has_shopfront, :has_hub_listing, :enterprise_category
|
||||
|
||||
def orders_close_at
|
||||
OrderCycle.first_closing_for(object).andand.orders_close_at
|
||||
end
|
||||
@@ -28,60 +25,6 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
@options[:active_distributors].andand.include? object
|
||||
end
|
||||
|
||||
def enterprise_category
|
||||
object.enterprise_category
|
||||
end
|
||||
|
||||
def has_shopfront
|
||||
object.is_distributor && object.type != 'profile'
|
||||
end
|
||||
|
||||
# Used to select enterprises for hub listing
|
||||
def has_hub_listing
|
||||
has_shopfront || object.enterprise_category == "hub_profile"
|
||||
end
|
||||
|
||||
# Map svg icons.
|
||||
def icon
|
||||
icons = {
|
||||
"hub" => "/assets/map_005-hub.svg",
|
||||
"hub_profile" => "/assets/map_006-hub-profile.svg",
|
||||
"producer_hub" => "/assets/map_005-hub.svg",
|
||||
"producer_shop" => "/assets/map_003-producer-shop.svg",
|
||||
"producer" => "/assets/map_001-producer-only.svg",
|
||||
"producer_profile" => "/assets/map_002-producer-only-profile.svg",
|
||||
}
|
||||
icons[object.enterprise_category]
|
||||
end
|
||||
|
||||
# Choose regular icon font for enterprises.
|
||||
def icon_font
|
||||
icon_fonts = {
|
||||
"hub" => "ofn-i_063-hub",
|
||||
"hub_profile" => "ofn-i_064-hub-reversed",
|
||||
"producer_hub" => "ofn-i_063-hub",
|
||||
"producer_shop" => "ofn-i_059-producer",
|
||||
"producer" => "ofn-i_059-producer",
|
||||
"producer_profile" => "ofn-i_060-producer-reversed",
|
||||
}
|
||||
icon_fonts[object.enterprise_category]
|
||||
end
|
||||
|
||||
# Choose producer page icon font - yes, sadly its got to be different.
|
||||
# This duplicates some code but covers the producer page edge case where
|
||||
# producer-hub has a producer icon without needing to duplicate the category logic in angular.
|
||||
def producer_icon_font
|
||||
icon_fonts = {
|
||||
"hub" => "",
|
||||
"hub_profile" => "",
|
||||
"producer_hub" => "ofn-i_059-producer",
|
||||
"producer_shop" => "ofn-i_059-producer",
|
||||
"producer" => "ofn-i_059-producer",
|
||||
"producer_profile" => "ofn-i_060-producer-reversed",
|
||||
"empty" => "",
|
||||
}
|
||||
icon_fonts[object.enterprise_category]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -92,8 +35,8 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
attributes :name, :id, :description, :latitude, :longitude,
|
||||
:long_description, :website, :instagram, :linkedin, :twitter,
|
||||
:facebook, :is_primary_producer, :is_distributor, :phone, :visible,
|
||||
:email, :hash, :logo, :promo_image, :path,
|
||||
:pickup, :delivery
|
||||
:email, :hash, :logo, :promo_image, :path, :pickup, :delivery,
|
||||
:icon, :icon_font, :producer_icon_font, :category
|
||||
|
||||
has_many :distributed_taxons, key: :taxons, serializer: Api::IdSerializer
|
||||
has_many :supplied_taxons, serializer: Api::IdSerializer
|
||||
@@ -131,4 +74,42 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
def path
|
||||
"/enterprises/#{object.to_param}/shop"
|
||||
end
|
||||
|
||||
# Map svg icons.
|
||||
def icon
|
||||
icons = {
|
||||
:hub => "/assets/map_005-hub.svg",
|
||||
:hub_profile => "/assets/map_006-hub-profile.svg",
|
||||
:producer_hub => "/assets/map_005-hub.svg",
|
||||
:producer_shop => "/assets/map_003-producer-shop.svg",
|
||||
:producer => "/assets/map_001-producer-only.svg",
|
||||
}
|
||||
icons[object.category]
|
||||
end
|
||||
|
||||
# Choose regular icon font for enterprises.
|
||||
def icon_font
|
||||
icon_fonts = {
|
||||
:hub => "ofn-i_063-hub",
|
||||
:hub_profile => "ofn-i_064-hub-reversed",
|
||||
:producer_hub => "ofn-i_063-hub",
|
||||
:producer_shop => "ofn-i_059-producer",
|
||||
:producer => "ofn-i_059-producer",
|
||||
}
|
||||
icon_fonts[object.category]
|
||||
end
|
||||
|
||||
# Choose producer page icon font - yes, sadly its got to be different.
|
||||
# This duplicates some code but covers the producer page edge case where
|
||||
# producer-hub has a producer icon without needing to duplicate the category logic in angular.
|
||||
def producer_icon_font
|
||||
icon_fonts = {
|
||||
:hub => "",
|
||||
:hub_profile => "",
|
||||
:producer_hub => "ofn-i_059-producer",
|
||||
:producer_shop => "ofn-i_059-producer",
|
||||
:producer => "ofn-i_059-producer",
|
||||
}
|
||||
icon_fonts[object.category]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,13 +32,9 @@
|
||||
|
||||
.row
|
||||
.three.columns.alpha
|
||||
%label Enterprise Type(s)
|
||||
.with-tip{'data-powertip' => "Select 'Producer' if you are a primary producer of food. Select 'Hub' if you want a shop-front. You can choose either or both."}
|
||||
%label Primary Producer
|
||||
.with-tip{'data-powertip' => "Select 'Producer' if you are a primary producer of food."}
|
||||
%a What's this?
|
||||
.two.columns
|
||||
= f.check_box :is_distributor, 'ng-model' => 'Enterprise.is_distributor'
|
||||
|
||||
= f.label :is_distributor, 'Hub'
|
||||
.five.columns.omega
|
||||
= f.check_box :is_primary_producer, 'ng-model' => 'Enterprise.is_primary_producer'
|
||||
|
||||
@@ -47,21 +43,21 @@
|
||||
.row
|
||||
.alpha.eleven.columns
|
||||
.three.columns.alpha
|
||||
= f.label :type, 'Profile type'
|
||||
.with-tip{'data-powertip' => "Full - enterprise may have products and relationships.<br />Single - enterprise may have products but no relationships.<br />Profile - enterprise has a profile but no products or relationships.<br />"}
|
||||
= f.label :sells, 'Sells'
|
||||
.with-tip{'data-powertip' => "None - enterprise does not sell to customers directly.<br />Own - Enterprise sells own products to customers.<br />Any - Enterprise can sell own or other enterprises products.<br />"}
|
||||
%a What's this?
|
||||
.two.columns
|
||||
= f.radio_button :type, "full"
|
||||
= f.radio_button :sells, "none", 'ng-model' => 'Enterprise.sells'
|
||||
|
||||
= f.label :type, "Full", value: "full"
|
||||
= f.label :sells, "None", value: "none"
|
||||
.two.columns
|
||||
= f.radio_button :type, "single"
|
||||
= f.radio_button :sells, "own", 'ng-model' => 'Enterprise.sells'
|
||||
|
||||
= f.label :type, "Single", value: "single"
|
||||
= f.label :sells, "Own", value: "own"
|
||||
.four.columns.omega
|
||||
= f.radio_button :type, "profile"
|
||||
= f.radio_button :sells, "any", 'ng-model' => 'Enterprise.sells'
|
||||
|
||||
= f.label :type, "Profile", value: "profile"
|
||||
= f.label :sells, "Any", value: "any"
|
||||
.row
|
||||
.three.columns.alpha
|
||||
%label Visible in search?
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
- if can? :admin, EnterpriseFee
|
||||
= render 'sidebar_enterprise_fees', f: f
|
||||
- if can? :admin, Spree::PaymentMethod
|
||||
= render 'sidebar_payment_methods', f: f
|
||||
- if can? :admin, Spree::ShippingMethod
|
||||
= render 'sidebar_shipping_methods', f: f
|
||||
- if can? :admin, EnterpriseFee
|
||||
= render 'sidebar_enterprise_fees', f: f
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
- enterprise_fees_color = @enterprise_fees.count > 0 ? "blue" : "red"
|
||||
.sidebar_item.four.columns.alpha#enterprise_fees{ ng: { show: 'Enterprise.is_distributor' } }
|
||||
.sidebar_item.four.columns.alpha#enterprise_fees{ ng: { show: 'Enterprise.category != "producer_hub"' } }
|
||||
.four.columns.alpha.header{ class: "#{enterprise_fees_color}" }
|
||||
%span.four.columns.alpha.centered Enterprise Fees
|
||||
.four.columns.alpha.list{ class: "#{enterprise_fees_color}" }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.sidebar_item.four.columns.alpha#payment_methods{ ng: { show: 'Enterprise.is_distributor' } }
|
||||
.sidebar_item.four.columns.alpha#payment_methods{ ng: { show: 'Enterprise.sells != "none"' } }
|
||||
.four.columns.alpha.header{ ng: { class: "paymentMethodsColor()" } }
|
||||
%span.four.columns.alpha.centered Payment Methods
|
||||
.four.columns.alpha.list{ ng: { class: "paymentMethodsColor()" } }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.sidebar_item.four.columns.alpha#shipping_methods{ ng: { show: 'Enterprise.is_distributor' } }
|
||||
.sidebar_item.four.columns.alpha#shipping_methods{ ng: { show: 'Enterprise.sells != "none"' } }
|
||||
.four.columns.alpha.header{ ng: { class: "shippingMethodsColor()" } }
|
||||
%span.four.columns.alpha.centered Shipping Methods
|
||||
.four.columns.alpha.list{ ng: { class: "shippingMethodsColor()" } }
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
%tr{"data-hook" => "enterprises_header"}
|
||||
%th Name
|
||||
%th Role
|
||||
%th Visible?
|
||||
- if spree_current_user.admin?
|
||||
%th Type
|
||||
%th Sells
|
||||
%th Visible?
|
||||
- if spree_current_user.admin?
|
||||
%th Owner
|
||||
%th
|
||||
@@ -37,12 +37,9 @@
|
||||
%td
|
||||
= enterprise_form.check_box :is_primary_producer
|
||||
Producer
|
||||
%br/
|
||||
= enterprise_form.check_box :is_distributor
|
||||
Hub
|
||||
%td= enterprise_form.check_box :visible
|
||||
- if spree_current_user.admin?
|
||||
%td= enterprise_form.select :type, Enterprise::TYPES, {}, class: 'select2 fullwidth'
|
||||
%td= enterprise_form.select :sells, Enterprise::SELLS, {}, class: 'select2 fullwidth'
|
||||
%td= enterprise_form.check_box :visible
|
||||
- if spree_current_user.admin?
|
||||
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"
|
||||
%td{"data-hook" => "admin_users_index_row_actions"}
|
||||
|
||||
@@ -40,8 +40,9 @@
|
||||
%h5 Our hubs & producers
|
||||
%ul.small-block-grid-2
|
||||
%li{"ng-repeat" => "enterprise in group.enterprises", "scroll-after-load" => true}
|
||||
%hub-modal{"ng-if" => "enterprise.is_distributor"}
|
||||
%producer-modal{"ng-if" => "!enterprise.is_distributor", "show-hub-actions" => 'true'}
|
||||
%enterprise-modal{"ng-if" => "enterprise.is_distributor"}
|
||||
{{ enterprise.name }}
|
||||
%enterprise-modal{"ng-if" => "!enterprise.is_distributor", "show-hub-actions" => 'true'}
|
||||
{{ enterprise.name }}
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
%label Our producers
|
||||
%ul.small-block-grid-2.medium-block-grid-1.large-block-grid-2
|
||||
%li{"ng-repeat" => "enterprise in hub.producers"}
|
||||
%producer-modal
|
||||
%enterprise-modal
|
||||
%i.ofn-i_036-producers
|
||||
%span
|
||||
{{ enterprise.name }}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
.light Filter by
|
||||
Type
|
||||
%ul.small-block-grid-2.medium-block-grid-4.large-block-grid-5
|
||||
%taxon-selector{objects: "hubs | hubs:query",
|
||||
%taxon-selector{objects: "Enterprises.hubs | searchEnterprises:query",
|
||||
results: "activeTaxons"}
|
||||
.small-12.large-3.columns
|
||||
%h5.tdhead
|
||||
|
||||
@@ -1,24 +1,17 @@
|
||||
= inject_enterprises
|
||||
#hubs.hubs{"ng-controller" => "HubsCtrl"}
|
||||
= inject_enterprises
|
||||
#hubs.hubs{"ng-controller" => "EnterprisesCtrl"}
|
||||
.row
|
||||
.small-12.columns
|
||||
%h1 Shop in your local area
|
||||
|
||||
#active-table-search.row.pad-top
|
||||
.small-12.columns
|
||||
%input{type: :text,
|
||||
"ng-model" => "query",
|
||||
placeholder: "Search by name or suburb...",
|
||||
"ng-debounce" => "150",
|
||||
"ofn-disable-enter" => true}
|
||||
|
||||
= render partial: "shared/components/enterprise_search"
|
||||
= render partial: "home/filters"
|
||||
|
||||
.row{bindonce: true}
|
||||
.small-12.columns
|
||||
.active_table
|
||||
%hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredHubs = (hubs | hubs:query | taxons:activeTaxons | shipping:shippingTypes | showProfiles:show_profiles )",
|
||||
"ng-class" => "{'is_profile' : !hub.has_shopfront, 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
|
||||
%hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (Enterprises.hubs | visible | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+orders_close_at'])",
|
||||
"ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
|
||||
"scroll-after-load" => true,
|
||||
"ng-controller" => "HubNodeCtrl",
|
||||
id: "{{hub.hash}}"}
|
||||
@@ -26,9 +19,4 @@
|
||||
= render partial: 'home/skinny'
|
||||
= render partial: 'home/fat'
|
||||
|
||||
.row{"ng-show" => "filteredHubs.length == 0"}
|
||||
.columns.small-12
|
||||
%p.no-results
|
||||
Sorry, no results found for
|
||||
%strong {{query}}.
|
||||
Try another search?
|
||||
= render partial: 'shared/components/enterprise_no_results'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.row.active_table_row{"ng-if" => "hub.has_shopfront", "ng-click" => "toggle()", "ng-class" => "{'closed' : !open(), 'has_shopfront' : producer.has_shopfront}", bindonce: true}
|
||||
.row.active_table_row{"ng-if" => "hub.is_distributor", "ng-click" => "toggle()", "ng-class" => "{'closed' : !open(), 'is_distributor' : producer.is_distributor}", bindonce: true}
|
||||
|
||||
.columns.small-12.medium-6.large-5.skinny-head
|
||||
%a.hub{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
|
||||
@@ -24,7 +24,7 @@
|
||||
%em Shopping here
|
||||
%span.margin-top{ bo: { if: "!current()" } } Orders closed
|
||||
|
||||
.row.active_table_row{"ng-if" => "!hub.has_shopfront", "ng-class" => "closed"}
|
||||
.row.active_table_row{"ng-if" => "!hub.is_distributor", "ng-class" => "closed"}
|
||||
.columns.small-12.medium-6.large-5.skinny-head
|
||||
%a.hub{"ng-click" => "openModal(hub)", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
|
||||
%i{ng: {class: "hub.icon_font"}}
|
||||
|
||||
@@ -21,9 +21,9 @@ node :promo_image do |enterprise|
|
||||
end
|
||||
|
||||
node :icon do |e|
|
||||
if e.is_primary_producer? and e.is_distributor?
|
||||
if e.is_primary_producer and e.is_distributor
|
||||
image_path "map_003-producer-shop.svg"
|
||||
elsif e.is_primary_producer?
|
||||
elsif e.is_primary_producer
|
||||
image_path "map_001-producer-only.svg"
|
||||
else
|
||||
image_path "map_005-hub.svg"
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
%ofn-modal{title: "{{enterprise.name}}"}
|
||||
.highlight
|
||||
.highlight-top
|
||||
%p.right
|
||||
{{ [enterprise.address.city, enterprise.address.state_name] | printArray}}
|
||||
%h3
|
||||
%i.ofn-i_036-producers
|
||||
{{ enterprise.name }}
|
||||
%img.hero-img{"ng-src" => "{{enterprise.promo_image}}"}
|
||||
|
||||
.row{bindonce: true}
|
||||
.small-12.large-8.columns
|
||||
%div{"ng-show" => "enterprise.long_description.length > 0 || enterprise.logo"}
|
||||
%p.modal-header About
|
||||
.about-container
|
||||
%img.enterprise-logo{"bo-src" => "enterprise.logo", "bo-if" => "enterprise.logo"}
|
||||
%p.text-small{"ng-bind-html" => "enterprise.long_description"}
|
||||
|
||||
.small-12.large-4.columns
|
||||
%div.modal-centered{"bo-if" => "enterprise.email || enterprise.website || enterprise.phone"}
|
||||
%p.modal-header Contact
|
||||
%p{"bo-if" => "enterprise.phone"}
|
||||
{{ enterprise.phone }}
|
||||
|
||||
%p{"bo-if" => "enterprise.email"}
|
||||
%a{"ng-href" => "{{enterprise.email | stripUrl}}", target: "_blank", mailto: true }
|
||||
%span.email
|
||||
{{ enterprise.email | stripUrl }}
|
||||
|
||||
%p{"bo-show" => "enterprise.website"}
|
||||
%a{"ng-href" => "http://{{enterprise.website}}", target: "_blank" }
|
||||
{{ enterprise.website | stripUrl }}
|
||||
|
||||
%div.modal-centered{"bo-if" => "enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
|
||||
%p.modal-header Follow
|
||||
.follow-icons{bindonce: true}
|
||||
%span{"bo-show" => "enterprise.twitter"}
|
||||
%a{"ng-href" => "http://twitter.com/{{enterprise.twitter}}", target: "_blank"}
|
||||
%i.ofn-i_041-twitter
|
||||
|
||||
%span{"bo-show" => "enterprise.facebook"}
|
||||
%a{"ng-href" => "http://{{enterprise.facebook | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_044-facebook
|
||||
|
||||
%span{"bo-show" => "enterprise.linkedin"}
|
||||
%a{"ng-href" => "http://{{enterprise.linkedin | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_042-linkedin
|
||||
|
||||
%span{"bo-show" => "enterprise.instagram"}
|
||||
%a{"ng-href" => "http://instagram.com/{{enterprise.instagram}}", target: "_blank"}
|
||||
%i.ofn-i_043-instagram
|
||||
|
||||
%a.close-reveal-modal{"ng-click" => "$close()"}
|
||||
%i.ofn-i_009-close
|
||||
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
.light Filter by
|
||||
Type
|
||||
%ul.small-block-grid-2.medium-block-grid-4.large-block-grid-6
|
||||
%taxon-selector{objects: "Producers.visible | filterProducers:query ",
|
||||
%taxon-selector{objects: "Enterprises.producers | searchEnterprises:query ",
|
||||
results: "activeTaxons"}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
.row.active_table_row{"ng-click" => "toggle()", "ng-class" => "{'closed' : !open(), 'has_shopfront' : producer.has_shopfront}"}
|
||||
.row.active_table_row{"ng-click" => "toggle()", "ng-class" => "{'closed' : !open(), 'is_distributor' : producer.is_distributor}"}
|
||||
.columns.small-12.medium-4.large-4.skinny-head
|
||||
%span{"bo-if" => "producer.has_shopfront" }
|
||||
%a.has_shopfront{"bo-href" => "producer.path" }
|
||||
%span{"bo-if" => "producer.is_distributor" }
|
||||
%a.is_distributor{"bo-href" => "producer.path" }
|
||||
%i{ng: {class: "producer.producer_icon_font"}}
|
||||
%span.margin-top
|
||||
%strong {{ producer.name }}
|
||||
%span.producer-name{"bo-if" => "!producer.has_shopfront" }
|
||||
%span.producer-name{"bo-if" => "!producer.is_distributor" }
|
||||
%i{ng: {class: "producer.producer_icon_font"}}
|
||||
%span.margin-top
|
||||
%strong {{ producer.name }}
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
= inject_enterprises
|
||||
.producers.pad-top{"ng-controller" => "ProducersCtrl"}
|
||||
= inject_enterprises
|
||||
.producers.pad-top{"ng-controller" => "EnterprisesCtrl"}
|
||||
.row
|
||||
.small-12.columns.pad-top
|
||||
%h1 Find local producers
|
||||
/ %div
|
||||
/ Find a
|
||||
/ %ofn-modal{title: "producer"}
|
||||
/ = render partial: "modals/producers"
|
||||
/ from the list below:
|
||||
|
||||
#active-table-search.row
|
||||
.small-12.columns
|
||||
%input.animate-show{type: :text,
|
||||
"ng-model" => "query",
|
||||
placeholder: "Search by producer or suburb...",
|
||||
"ng-debounce" => "150",
|
||||
"ofn-disable-enter" => true}
|
||||
|
||||
= render partial: "shared/components/enterprise_search"
|
||||
= render partial: "producers/filters"
|
||||
|
||||
.row{bindonce: true}
|
||||
@@ -24,7 +12,7 @@
|
||||
.active_table
|
||||
%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}",
|
||||
"scroll-after-load" => true,
|
||||
"ng-repeat" => "producer in producers = (Producers.visible | filterProducers:query | taxons:activeTaxons)",
|
||||
"ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons)",
|
||||
"ng-controller" => "ProducerNodeCtrl",
|
||||
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}",
|
||||
id: "{{producer.hash}}"}
|
||||
@@ -33,10 +21,6 @@
|
||||
= render partial: 'producers/skinny'
|
||||
= render partial: 'producers/fat'
|
||||
|
||||
%producer.row{"ng-show" => "producers.length == 0"}
|
||||
%p.no-results
|
||||
Sorry, no results found for
|
||||
%strong {{query}}.
|
||||
Try another search?
|
||||
= render partial: 'shared/components/enterprise_no_results'
|
||||
|
||||
= render partial: "shared/footer"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
%producer.row{"ng-show" => "filteredEnterprises.length == 0"}
|
||||
%p.no-results
|
||||
Sorry, no results found for
|
||||
%strong {{query}}.
|
||||
Try another search?
|
||||
7
app/views/shared/components/_enterprise_search.html.haml
Normal file
7
app/views/shared/components/_enterprise_search.html.haml
Normal file
@@ -0,0 +1,7 @@
|
||||
#active-table-search.row
|
||||
.small-12.columns
|
||||
%input{type: :text,
|
||||
"ng-model" => "query",
|
||||
placeholder: "Search by name or suburb...",
|
||||
"ng-debounce" => "150",
|
||||
"ofn-disable-enter" => true}
|
||||
@@ -1,6 +1,7 @@
|
||||
.small-12.medium-6.columns.text-right
|
||||
.profile-checkbox
|
||||
%input{"ng-model" => "show_profiles", type: "checkbox", name: "profile"}><
|
||||
%label Show profiles
|
||||
%button.button.secondary.tiny.help-btn.ng-scope{:popover => "Profiles do not have a shopfront on the Open Food Network, but may have their own physical or online shop elsewhere", "popover-placement" => "left"}><
|
||||
%i.ofn-i_013-help
|
||||
%label
|
||||
%input{"ng-model" => "show_profiles", type: "checkbox", name: "profile"}
|
||||
Show profiles
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
%em from
|
||||
%span
|
||||
%producer-modal
|
||||
%enterprise-modal
|
||||
%i.ofn-i_036-producers
|
||||
{{ enterprise.name }}
|
||||
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
%h5 {{CurrentHub.hub.name}}'s producers:
|
||||
%ul.small-block-grid-2.large-block-grid-4
|
||||
%li{"ng-repeat" => "enterprise in CurrentHub.hub.producers"}
|
||||
%i.ofn-i_036-producers
|
||||
= render partial: "modals/producer"
|
||||
%enterprise-modal
|
||||
%i.ofn-i_036-producers
|
||||
{{ enterprise.name }}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#tabs{"ng-controller" => "TabsCtrl"}
|
||||
.row
|
||||
%tabset.small-12.columns
|
||||
// WILL can we add some logic here to make the distributor name not appear at small sizes? e.g. add a class?)
|
||||
-# Build all tabs.
|
||||
- for name, heading in { about: "About #{current_distributor.name}",
|
||||
producers: "Producers",
|
||||
groups: "Groups",
|
||||
contact: "Contact"}
|
||||
|
||||
-# tabs take tab path in 'active' and 'select' functions defined in TabsCtrl.
|
||||
%tab{heading: heading,
|
||||
id: "tab_#{name}",
|
||||
active: "active(#{name}.path)",
|
||||
select: "select(#{name})"}
|
||||
active: "active(\'#{name}\')",
|
||||
select: "select(\'#{name}\')"}
|
||||
= render "shopping_shared/#{name}"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
class AddDummyForMissingEmails < ActiveRecord::Migration
|
||||
def up
|
||||
Enterprise.all.each do |enterprise|
|
||||
enterprise.update_column(:email, "missing@example.com") if enterprise.read_attribute(:email).blank?
|
||||
end
|
||||
end
|
||||
end
|
||||
49
db/migrate/20140927005043_enterprise_config_refactor.rb
Normal file
49
db/migrate/20140927005043_enterprise_config_refactor.rb
Normal file
@@ -0,0 +1,49 @@
|
||||
class EnterpriseConfigRefactor < ActiveRecord::Migration
|
||||
def up
|
||||
add_column :enterprises, :sells, :string, null: false, default: 'none'
|
||||
add_index :enterprises, :sells
|
||||
add_index :enterprises, [:is_primary_producer, :sells]
|
||||
|
||||
Enterprise.all.each do |enterprise|
|
||||
enterprise.update_attributes!({:sells => sells_what?(enterprise)})
|
||||
end
|
||||
|
||||
remove_column :enterprises, :type
|
||||
remove_column :enterprises, :is_distributor
|
||||
end
|
||||
|
||||
def down
|
||||
# This process is lossy. Producer profiles wont exist.
|
||||
add_column :enterprises, :type, :string, null: false, default: 'profile'
|
||||
add_column :enterprises, :is_distributor, :boolean
|
||||
|
||||
Enterprise.all.each do |enterprise|
|
||||
enterprise.update_attributes!({
|
||||
:type => type?(enterprise),
|
||||
:is_distributor => distributes?(enterprise)
|
||||
})
|
||||
end
|
||||
|
||||
remove_column :enterprises, :sells
|
||||
end
|
||||
|
||||
def sells_what?(enterprise)
|
||||
is_distributor = enterprise.read_attribute(:is_distributor)
|
||||
is_primary_producer = enterprise.read_attribute(:is_primary_producer)
|
||||
type = enterprise.read_attribute(:type)
|
||||
return "own" if type == "single" && (is_distributor || is_primary_producer)
|
||||
return "none" if !is_distributor || type == "profile"
|
||||
return "any"
|
||||
end
|
||||
|
||||
def distributes?(enterprise)
|
||||
enterprise.read_attribute(:sells) != "none"
|
||||
end
|
||||
|
||||
def type?(enterprise)
|
||||
sells = enterprise.read_attribute(:sells)
|
||||
return "profile" if sells == "none"
|
||||
return "single" if sells == "own"
|
||||
return "full"
|
||||
end
|
||||
end
|
||||
13
db/schema.rb
13
db/schema.rb
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20140904003026) do
|
||||
ActiveRecord::Schema.define(:version => 20140927005043) do
|
||||
|
||||
create_table "adjustment_metadata", :force => true do |t|
|
||||
t.integer "adjustment_id"
|
||||
@@ -238,7 +238,6 @@ ActiveRecord::Schema.define(:version => 20140904003026) do
|
||||
t.string "description"
|
||||
t.text "long_description"
|
||||
t.boolean "is_primary_producer"
|
||||
t.boolean "is_distributor"
|
||||
t.string "contact"
|
||||
t.string "phone"
|
||||
t.string "email"
|
||||
@@ -249,8 +248,8 @@ ActiveRecord::Schema.define(:version => 20140904003026) do
|
||||
t.integer "address_id"
|
||||
t.string "pickup_times"
|
||||
t.string "next_collection_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.text "distributor_info"
|
||||
t.string "logo_file_name"
|
||||
t.string "logo_content_type"
|
||||
@@ -264,12 +263,14 @@ ActiveRecord::Schema.define(:version => 20140904003026) do
|
||||
t.string "facebook"
|
||||
t.string "instagram"
|
||||
t.string "linkedin"
|
||||
t.string "type", :default => "profile", :null => false
|
||||
t.integer "owner_id", :null => false
|
||||
t.integer "owner_id", :null => false
|
||||
t.string "sells", :default => "none", :null => false
|
||||
end
|
||||
|
||||
add_index "enterprises", ["address_id"], :name => "index_enterprises_on_address_id"
|
||||
add_index "enterprises", ["is_primary_producer", "sells"], :name => "index_enterprises_on_is_primary_producer_and_sells"
|
||||
add_index "enterprises", ["owner_id"], :name => "index_enterprises_on_owner_id"
|
||||
add_index "enterprises", ["sells"], :name => "index_enterprises_on_sells"
|
||||
|
||||
create_table "exchange_fees", :force => true do |t|
|
||||
t.integer "exchange_id"
|
||||
|
||||
@@ -84,28 +84,28 @@ module Admin
|
||||
end
|
||||
|
||||
describe "updating an enterprise" do
|
||||
let(:profile_enterprise) { create(:enterprise, type: 'profile') }
|
||||
let(:profile_enterprise) { create(:enterprise, sells: 'none') }
|
||||
|
||||
context "as manager" do
|
||||
it "does not allow 'type' to be changed" do
|
||||
it "does not allow 'sells' to be changed" do
|
||||
profile_enterprise.enterprise_roles.build(user: user).save
|
||||
controller.stub spree_current_user: user
|
||||
enterprise_params = { id: profile_enterprise.id, enterprise: { type: 'full' } }
|
||||
enterprise_params = { id: profile_enterprise.id, enterprise: { sells: 'any' } }
|
||||
|
||||
spree_put :update, enterprise_params
|
||||
profile_enterprise.reload
|
||||
expect(profile_enterprise.type).to eq 'profile'
|
||||
expect(profile_enterprise.sells).to eq 'none'
|
||||
end
|
||||
end
|
||||
|
||||
context "as super admin" do
|
||||
it "allows 'type' to be changed" do
|
||||
it "allows 'sells' to be changed" do
|
||||
controller.stub spree_current_user: admin_user
|
||||
enterprise_params = { id: profile_enterprise.id, enterprise: { type: 'full' } }
|
||||
enterprise_params = { id: profile_enterprise.id, enterprise: { sells: 'any' } }
|
||||
|
||||
spree_put :update, enterprise_params
|
||||
profile_enterprise.reload
|
||||
expect(profile_enterprise.type).to eq 'full'
|
||||
expect(profile_enterprise.sells).to eq 'any'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -123,38 +123,38 @@ module Admin
|
||||
user.save!
|
||||
user
|
||||
end
|
||||
let!(:profile_enterprise1) { create(:enterprise, type: 'profile', owner: original_owner ) }
|
||||
let!(:profile_enterprise2) { create(:enterprise, type: 'profile', owner: original_owner ) }
|
||||
let!(:profile_enterprise1) { create(:enterprise, sells: 'none', owner: original_owner ) }
|
||||
let!(:profile_enterprise2) { create(:enterprise, sells: 'none', owner: original_owner ) }
|
||||
|
||||
context "as manager" do
|
||||
it "does not allow 'type' or 'owner' to be changed" do
|
||||
it "does not allow 'sells' or 'owner' to be changed" do
|
||||
profile_enterprise1.enterprise_roles.build(user: new_owner).save
|
||||
profile_enterprise2.enterprise_roles.build(user: new_owner).save
|
||||
controller.stub spree_current_user: new_owner
|
||||
bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, type: 'full', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, type: 'full', owner_id: new_owner.id } } } }
|
||||
bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } }
|
||||
|
||||
spree_put :bulk_update, bulk_enterprise_params
|
||||
profile_enterprise1.reload
|
||||
profile_enterprise2.reload
|
||||
expect(profile_enterprise1.type).to eq 'profile'
|
||||
expect(profile_enterprise2.type).to eq 'profile'
|
||||
expect(profile_enterprise1.sells).to eq 'none'
|
||||
expect(profile_enterprise2.sells).to eq 'none'
|
||||
expect(profile_enterprise1.owner).to eq original_owner
|
||||
expect(profile_enterprise2.owner).to eq original_owner
|
||||
end
|
||||
end
|
||||
|
||||
context "as super admin" do
|
||||
it "allows 'type' and 'owner' to be changed" do
|
||||
it "allows 'sells' and 'owner' to be changed" do
|
||||
profile_enterprise1.enterprise_roles.build(user: new_owner).save
|
||||
profile_enterprise2.enterprise_roles.build(user: new_owner).save
|
||||
controller.stub spree_current_user: admin_user
|
||||
bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, type: 'full', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, type: 'full', owner_id: new_owner.id } } } }
|
||||
bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } }
|
||||
|
||||
spree_put :bulk_update, bulk_enterprise_params
|
||||
profile_enterprise1.reload
|
||||
profile_enterprise2.reload
|
||||
expect(profile_enterprise1.type).to eq 'full'
|
||||
expect(profile_enterprise2.type).to eq 'full'
|
||||
expect(profile_enterprise1.sells).to eq 'any'
|
||||
expect(profile_enterprise2.sells).to eq 'any'
|
||||
expect(profile_enterprise1.owner).to eq new_owner
|
||||
expect(profile_enterprise2.owner).to eq new_owner
|
||||
end
|
||||
|
||||
@@ -73,4 +73,4 @@ describe Spree::Admin::PaymentMethodsController do
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -92,7 +92,7 @@ FactoryGirl.define do
|
||||
factory :enterprise, :class => Enterprise do
|
||||
owner { FactoryGirl.create :user }
|
||||
sequence(:name) { |n| "Enterprise #{n}" }
|
||||
type 'full'
|
||||
sells 'any'
|
||||
description 'enterprise'
|
||||
long_description '<p>Hello, world!</p><p>This is a paragraph.</p>'
|
||||
email 'enterprise@example.com'
|
||||
@@ -101,12 +101,12 @@ FactoryGirl.define do
|
||||
|
||||
factory :supplier_enterprise, :parent => :enterprise do
|
||||
is_primary_producer true
|
||||
is_distributor false
|
||||
sells "none"
|
||||
end
|
||||
|
||||
factory :distributor_enterprise, :parent => :enterprise do
|
||||
is_primary_producer false
|
||||
is_distributor true
|
||||
sells "any"
|
||||
end
|
||||
|
||||
factory :enterprise_relationship do
|
||||
|
||||
@@ -11,10 +11,10 @@ feature %q{
|
||||
let!(:user) { create_enterprise_user }
|
||||
let!(:supplier1) { create(:supplier_enterprise, name: 'Supplier 1') }
|
||||
let!(:supplier2) { create(:supplier_enterprise, name: 'Supplier 2') }
|
||||
let(:supplier_profile) { create(:supplier_enterprise, name: 'Supplier profile', type: 'profile') }
|
||||
let(:supplier_profile) { create(:supplier_enterprise, name: 'Supplier profile', sells: 'none') }
|
||||
let!(:distributor1) { create(:distributor_enterprise, name: 'Distributor 3') }
|
||||
let!(:distributor2) { create(:distributor_enterprise, name: 'Distributor 4') }
|
||||
let(:distributor_profile) { create(:distributor_enterprise, name: 'Distributor profile', type: 'profile') }
|
||||
let(:distributor_profile) { create(:distributor_enterprise, name: 'Distributor profile', sells: 'none') }
|
||||
|
||||
describe "creating an enterprise user" do
|
||||
context "with a limitted number of owned enterprises" do
|
||||
@@ -53,7 +53,10 @@ feature %q{
|
||||
end
|
||||
end
|
||||
|
||||
describe "with only a profile-level enterprise" do
|
||||
# This case no longer exists as anyone with an enterprise can supply into the system.
|
||||
# Or can they?? There is no producer profile anyway.
|
||||
# TODO discuss what parts of this are still necessary in which cases.
|
||||
pending "with only a profile-level enterprise" do
|
||||
before do
|
||||
user.enterprise_roles.create! enterprise: supplier_profile
|
||||
user.enterprise_roles.create! enterprise: distributor_profile
|
||||
|
||||
@@ -16,7 +16,7 @@ feature %q{
|
||||
|
||||
within("tr.enterprise-#{s.id}") do
|
||||
expect(page).to have_content s.name
|
||||
expect(page).to have_select "enterprise_set_collection_attributes_1_type"
|
||||
expect(page).to have_select "enterprise_set_collection_attributes_1_sells"
|
||||
expect(page).to have_content "Edit Profile"
|
||||
expect(page).to have_content "Delete"
|
||||
expect(page).to_not have_content "Payment Methods"
|
||||
@@ -26,7 +26,7 @@ feature %q{
|
||||
|
||||
within("tr.enterprise-#{d.id}") do
|
||||
expect(page).to have_content d.name
|
||||
expect(page).to have_select "enterprise_set_collection_attributes_0_type"
|
||||
expect(page).to have_select "enterprise_set_collection_attributes_0_sells"
|
||||
expect(page).to have_content "Edit Profile"
|
||||
expect(page).to have_content "Delete"
|
||||
expect(page).to have_content "Payment Methods"
|
||||
@@ -37,7 +37,7 @@ feature %q{
|
||||
|
||||
scenario "editing enterprises in bulk" do
|
||||
s = create(:supplier_enterprise)
|
||||
d = create(:distributor_enterprise, type: 'profile')
|
||||
d = create(:distributor_enterprise, sells: 'none')
|
||||
d_manager = create_enterprise_user
|
||||
d_manager.enterprise_roles.build(enterprise: d).save
|
||||
expect(d.owner).to_not eq d_manager
|
||||
@@ -48,14 +48,14 @@ feature %q{
|
||||
within("tr.enterprise-#{d.id}") do
|
||||
expect(page).to have_checked_field "enterprise_set_collection_attributes_0_visible"
|
||||
uncheck "enterprise_set_collection_attributes_0_visible"
|
||||
select 'full', from: "enterprise_set_collection_attributes_0_type"
|
||||
select 'any', from: "enterprise_set_collection_attributes_0_sells"
|
||||
select d_manager.email, from: 'enterprise_set_collection_attributes_0_owner_id'
|
||||
end
|
||||
click_button "Update"
|
||||
flash_message.should == 'Enterprises updated successfully'
|
||||
distributor = Enterprise.find(d.id)
|
||||
expect(distributor.visible).to eq false
|
||||
expect(distributor.type).to eq 'full'
|
||||
expect(distributor.sells).to eq 'any'
|
||||
expect(distributor.owner).to eq d_manager
|
||||
end
|
||||
|
||||
@@ -82,15 +82,16 @@ feature %q{
|
||||
click_link 'New Enterprise'
|
||||
|
||||
# Checking shipping and payment method sidebars work
|
||||
choose "Any"
|
||||
uncheck 'enterprise_is_primary_producer'
|
||||
check 'enterprise_is_distributor'
|
||||
|
||||
page.should_not have_checked_field "enterprise_payment_method_ids_#{payment_method.id}"
|
||||
page.should_not have_checked_field "enterprise_shipping_method_ids_#{shipping_method.id}"
|
||||
|
||||
# Filling in details
|
||||
fill_in 'enterprise_name', :with => 'Eaterprises'
|
||||
select2_search admin.email, from: 'Owner'
|
||||
choose 'Full'
|
||||
choose 'Any'
|
||||
check "enterprise_payment_method_ids_#{payment_method.id}"
|
||||
check "enterprise_shipping_method_ids_#{shipping_method.id}"
|
||||
select2_search eg1.name, from: 'Groups'
|
||||
@@ -134,7 +135,7 @@ feature %q{
|
||||
end
|
||||
|
||||
fill_in 'enterprise_name', :with => 'Eaterprises'
|
||||
choose 'Single'
|
||||
choose 'Own'
|
||||
select2_search user.email, from: 'Owner'
|
||||
fill_in 'enterprise_description', :with => 'Connecting farmers and eaters'
|
||||
long_description = find :css, "text-angular div.ta-scroll-window div.ta-bind"
|
||||
@@ -142,14 +143,23 @@ feature %q{
|
||||
|
||||
# Check Angularjs switching of sidebar elements
|
||||
uncheck 'enterprise_is_primary_producer'
|
||||
uncheck 'enterprise_is_distributor'
|
||||
choose 'None'
|
||||
page.should have_selector "#enterprise_fees", visible: false
|
||||
page.should have_selector "#payment_methods", visible: false
|
||||
page.should have_selector "#shipping_methods", visible: false
|
||||
page.should have_selector "#enterprise_fees", visible: false
|
||||
check 'enterprise_is_distributor'
|
||||
check 'enterprise_is_primary_producer'
|
||||
page.should have_selector "#enterprise_fees"
|
||||
page.should have_selector "#payment_methods", visible: false
|
||||
page.should have_selector "#shipping_methods", visible: false
|
||||
uncheck 'enterprise_is_primary_producer'
|
||||
choose 'Own'
|
||||
page.should have_selector "#enterprise_fees"
|
||||
page.should have_selector "#payment_methods"
|
||||
page.should have_selector "#shipping_methods"
|
||||
choose 'Any'
|
||||
page.should have_selector "#enterprise_fees"
|
||||
page.should have_selector "#payment_methods"
|
||||
page.should have_selector "#shipping_methods"
|
||||
|
||||
select2_search eg1.name, from: 'Groups'
|
||||
|
||||
@@ -277,16 +287,14 @@ feature %q{
|
||||
|
||||
within("tr.enterprise-#{distributor1.id}") do
|
||||
expect(page).to have_content distributor1.name
|
||||
expect(page).to have_checked_field "enterprise_set_collection_attributes_0_is_distributor"
|
||||
expect(page).to have_unchecked_field "enterprise_set_collection_attributes_0_is_primary_producer"
|
||||
expect(page).to_not have_select "enterprise_set_collection_attributes_0_type"
|
||||
expect(page).to_not have_select "enterprise_set_collection_attributes_0_sells"
|
||||
end
|
||||
|
||||
within("tr.enterprise-#{supplier1.id}") do
|
||||
expect(page).to have_content supplier1.name
|
||||
expect(page).to have_unchecked_field "enterprise_set_collection_attributes_1_is_distributor"
|
||||
expect(page).to have_checked_field "enterprise_set_collection_attributes_1_is_primary_producer"
|
||||
expect(page).to_not have_select "enterprise_set_collection_attributes_1_type"
|
||||
expect(page).to_not have_select "enterprise_set_collection_attributes_1_sells"
|
||||
end
|
||||
|
||||
expect(page).to_not have_content "supplier2.name"
|
||||
|
||||
@@ -3,7 +3,8 @@ require 'spec_helper'
|
||||
feature "Registration", js: true do
|
||||
include WebHelper
|
||||
|
||||
describe "Registering a Profile" do
|
||||
# TODO fix this after removal of is_distributor.
|
||||
pending "Registering a Profile" do
|
||||
let(:user) { create(:user, password: "password", password_confirmation: "password") }
|
||||
|
||||
it "Allows a logged in user to register a profile" do
|
||||
@@ -49,7 +50,7 @@ feature "Registration", js: true do
|
||||
expect(page).to have_content 'Nice one!'
|
||||
e = Enterprise.find_by_name('My Awesome Enterprise')
|
||||
expect(e.address.address1).to eq "123 Abc Street"
|
||||
expect(e.is_distributor).to eq true
|
||||
expect(e.sells).to eq "none"
|
||||
expect(e.is_primary_producer).to eq true
|
||||
expect(e.contact).to eq "Saskia Munroe"
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
visit shop_path
|
||||
end
|
||||
|
||||
it "should save group buy data to ze cart" do
|
||||
it "should save group buy data to the cart" do
|
||||
fill_in "variants[#{variant.id}]", with: 6
|
||||
fill_in "variant_attributes[#{variant.id}][max_quantity]", with: 7
|
||||
page.should have_in_cart product.name
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
describe 'filtering Hubs', ->
|
||||
filter = null
|
||||
filterHubs = null
|
||||
hubs = [{
|
||||
name: "frogs"
|
||||
other: "roger"
|
||||
address:
|
||||
zipcode: "cats"
|
||||
city: "cambridge"
|
||||
state: "kansas"
|
||||
}, {
|
||||
name: "donkeys"
|
||||
other: "roger"
|
||||
address:
|
||||
zipcode: ""
|
||||
city: "Wellington"
|
||||
state: "uzbekistan"
|
||||
}]
|
||||
|
||||
beforeEach ->
|
||||
module 'Darkswarm'
|
||||
inject ($filter) ->
|
||||
filter = $filter
|
||||
filterHubs = $filter('hubs')
|
||||
|
||||
it 'has a hub filter', ->
|
||||
expect(filter('hubs')).not.toBeNull()
|
||||
|
||||
it "filters by name", ->
|
||||
expect(filterHubs(hubs, 'donkeys').length).toEqual 1
|
||||
|
||||
it "is case insensitive", ->
|
||||
expect(filterHubs(hubs, 'DONKEYS').length).toEqual 1
|
||||
|
||||
it "filters by state", ->
|
||||
expect(filterHubs(hubs, 'kansas').length).toEqual 1
|
||||
|
||||
it "filters by zipcode", ->
|
||||
expect(filterHubs(hubs, 'cats').length).toEqual 1
|
||||
|
||||
it "gives all hubs when no argument is specified", ->
|
||||
expect(filterHubs(hubs, '').length).toEqual 2
|
||||
|
||||
it "does not filter by anything else", ->
|
||||
expect(filterHubs(hubs, 'roger').length).toEqual 0
|
||||
@@ -1,28 +0,0 @@
|
||||
describe 'filtering producers', ->
|
||||
filter = null
|
||||
filterProducers = null
|
||||
producers = [{
|
||||
name: "frogs"
|
||||
other: "roger"
|
||||
address:
|
||||
zipcode: "cats"
|
||||
city: "cambridge"
|
||||
state: "kansas"
|
||||
}, {
|
||||
name: "donkeys"
|
||||
other: "roger"
|
||||
address:
|
||||
zipcode: ""
|
||||
city: "Wellington"
|
||||
state: "uzbekistan"
|
||||
}]
|
||||
|
||||
beforeEach ->
|
||||
module 'Darkswarm'
|
||||
inject ($filter) ->
|
||||
filter = $filter
|
||||
filterProducers = $filter('filterProducers')
|
||||
|
||||
|
||||
it 'has a producer filter', ->
|
||||
expect(filter('filterProducers')).not.toBeNull()
|
||||
@@ -0,0 +1,40 @@
|
||||
describe 'filtering Enterprises', ->
|
||||
filter = null
|
||||
enterprises = [{
|
||||
name: "frogs"
|
||||
other: "roger"
|
||||
address:
|
||||
zipcode: "cats"
|
||||
city: "cambridge"
|
||||
state: "kansas"
|
||||
}, {
|
||||
name: "donkeys"
|
||||
other: "roger"
|
||||
address:
|
||||
zipcode: ""
|
||||
city: "Wellington"
|
||||
state: "uzbekistan"
|
||||
}]
|
||||
|
||||
beforeEach ->
|
||||
module 'Darkswarm'
|
||||
inject ($filter) ->
|
||||
filter = $filter('searchEnterprises')
|
||||
|
||||
it "filters by name", ->
|
||||
expect(filter(enterprises, 'donkeys').length).toEqual 1
|
||||
|
||||
it "is case insensitive", ->
|
||||
expect(filter(enterprises, 'DONKEYS').length).toEqual 1
|
||||
|
||||
it "filters by state", ->
|
||||
expect(filter(enterprises, 'kansas').length).toEqual 1
|
||||
|
||||
it "filters by zipcode", ->
|
||||
expect(filter(enterprises, 'cats').length).toEqual 1
|
||||
|
||||
it "gives all enterprises when no argument is specified", ->
|
||||
expect(filter(enterprises, '').length).toEqual 2
|
||||
|
||||
it "does not filter by anything else", ->
|
||||
expect(filter(enterprises, 'roger').length).toEqual 0
|
||||
@@ -1,24 +1,30 @@
|
||||
describe "Enterprises service", ->
|
||||
Enterprises = null
|
||||
CurrentHubMock = {}
|
||||
CurrentHubMock = {}
|
||||
taxons = [
|
||||
{id: 1, name: "test"}
|
||||
]
|
||||
enterprises = [
|
||||
{id: 1, type: "hub", producers: [{id: 2}], taxons: [{id: 1}]},
|
||||
{id: 2, type: "producer", hubs: [{id: 1}]},
|
||||
{id: 3, type: "producer", hubs: [{id: 1}]}
|
||||
{id: 1, visible: true, category: "hub", producers: [{id: 5}], taxons: [{id: 1}]},
|
||||
{id: 2, visible: true, category: "hub", producers: [{id: 6}]}
|
||||
{id: 3, visible: true, category: "hub_profile"}
|
||||
{id: 4, visible: false, category: "hub", producers: [{id: 7}]}
|
||||
{id: 5, visible: true, category: "producer_hub", hubs: [{id: 1}]},
|
||||
{id: 6, visible: true, category: "producer_shop", hubs: [{id: 2}]},
|
||||
{id: 7, visible: true, category: "producer", hubs: [{id: 2}]}
|
||||
{id: 8, visible: false, category: "producer", hubs: [{id: 2}]}
|
||||
]
|
||||
H1: 0
|
||||
beforeEach ->
|
||||
module 'Darkswarm'
|
||||
module ($provide)->
|
||||
$provide.value "CurrentHub", CurrentHubMock
|
||||
$provide.value "CurrentHub", CurrentHubMock
|
||||
null
|
||||
angular.module('Darkswarm').value('enterprises', enterprises)
|
||||
angular.module('Darkswarm').value('taxons', taxons)
|
||||
angular.module('Darkswarm').value('enterprises', enterprises)
|
||||
angular.module('Darkswarm').value('taxons', taxons)
|
||||
|
||||
inject ($injector)->
|
||||
Enterprises = $injector.get("Enterprises")
|
||||
Enterprises = $injector.get("Enterprises")
|
||||
|
||||
it "stores enterprises as id/object pairs", ->
|
||||
expect(Enterprises.enterprises_by_id["1"]).toBe enterprises[0]
|
||||
@@ -31,8 +37,39 @@ describe "Enterprises service", ->
|
||||
expect(Enterprises.enterprises[0]).toBe Enterprises.enterprises_by_id["1"]
|
||||
|
||||
it "dereferences references to other enterprises", ->
|
||||
expect(Enterprises.enterprises_by_id["1"].producers[0]).toBe enterprises[1]
|
||||
expect(Enterprises.enterprises_by_id["3"].hubs[0]).toBe enterprises[0]
|
||||
expect(Enterprises.enterprises_by_id["1"].producers[0]).toBe enterprises[4]
|
||||
expect(Enterprises.enterprises_by_id["5"].hubs[0]).toBe enterprises[0]
|
||||
|
||||
it "dereferences taxons", ->
|
||||
expect(Enterprises.enterprises[0].taxons[0]).toBe taxons[0]
|
||||
|
||||
it "filters Enterprise.hubs into a new array", ->
|
||||
expect(Enterprises.hubs[0]).toBe Enterprises.enterprises[0]
|
||||
# Because the $filter is a new sorted array
|
||||
# We check to see the objects in both arrays are still the same
|
||||
Enterprises.enterprises[0].active = false
|
||||
expect(Enterprises.hubs[0].active).toBe false
|
||||
|
||||
it "filters Enterprises.producers into a new array", ->
|
||||
expect(Enterprises.producers[0]).toBe Enterprises.enterprises[4]
|
||||
Enterprises.enterprises[4].active = false
|
||||
expect(Enterprises.producers[0].active).toBe false
|
||||
|
||||
it "only includes visible enterprises in hubs array", ->
|
||||
expect(Enterprises.hubs).toContain Enterprises.enterprises[0]
|
||||
expect(Enterprises.hubs).not.toContain Enterprises.enterprises[3]
|
||||
|
||||
it "only includes visible enterprises in producers array", ->
|
||||
expect(Enterprises.producers).toContain Enterprises.enterprises[4]
|
||||
expect(Enterprises.producers).not.toContain Enterprises.enterprises[7]
|
||||
|
||||
it "includes hub, hub_profile, producer_hub and, producer_shop enterprises in hubs array", ->
|
||||
expect(Enterprises.hubs).toContain Enterprises.enterprises[0]
|
||||
expect(Enterprises.hubs).toContain Enterprises.enterprises[2]
|
||||
expect(Enterprises.hubs).toContain Enterprises.enterprises[4]
|
||||
expect(Enterprises.hubs).toContain Enterprises.enterprises[5]
|
||||
|
||||
it "includes producer_hub, producer_shop and producer enterprises in producers array", ->
|
||||
expect(Enterprises.producers).toContain Enterprises.enterprises[4]
|
||||
expect(Enterprises.producers).toContain Enterprises.enterprises[5]
|
||||
expect(Enterprises.producers).toContain Enterprises.enterprises[6]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user