mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-15 19:06:50 +00:00
Compare commits
289 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43d3955627 | ||
|
|
6155600cb2 | ||
|
|
8385bff55e | ||
|
|
928e5dc474 | ||
|
|
cc0e205f50 | ||
|
|
80b36992f9 | ||
|
|
a157528974 | ||
|
|
8b819539e7 | ||
|
|
2eb152f63e | ||
|
|
c733ca251e | ||
|
|
d388747a81 | ||
|
|
8ac367675f | ||
|
|
96516a8ff3 | ||
|
|
3e002c6f82 | ||
|
|
20e2cb4ecc | ||
|
|
b0d8290dab | ||
|
|
8603cf685e | ||
|
|
b182c6afc8 | ||
|
|
0d73d8f043 | ||
|
|
498b51cedb | ||
|
|
01cb39a93f | ||
|
|
b172c4fd4f | ||
|
|
b3ac06e46c | ||
|
|
68cb3efc50 | ||
|
|
e32ab7b4b7 | ||
|
|
d0c3502f27 | ||
|
|
631386ced4 | ||
|
|
982be3a563 | ||
|
|
76c6c260d1 | ||
|
|
0b3e293b38 | ||
|
|
f40b4d9d03 | ||
|
|
900ef4ddcc | ||
|
|
911d1e3dc4 | ||
|
|
f03c7ba02d | ||
|
|
49a2b774b0 | ||
|
|
f6b0324456 | ||
|
|
46ab424655 | ||
|
|
d2efd25e8d | ||
|
|
3c839be743 | ||
|
|
cf06cab533 | ||
|
|
9bc8531850 | ||
|
|
ee5cd599aa | ||
|
|
aea8ab4c7f | ||
|
|
e1cf5ceb57 | ||
|
|
996b2f2604 | ||
|
|
d94ca0174a | ||
|
|
f09698be47 | ||
|
|
7faf6e12ea | ||
|
|
4f2327f05c | ||
|
|
d50cd023d4 | ||
|
|
ce346d3bca | ||
|
|
e67f039791 | ||
|
|
e9a6c9d0ce | ||
|
|
67c82e81de | ||
|
|
04af954432 | ||
|
|
bcc8198019 | ||
|
|
d6947b119f | ||
|
|
204c7d9690 | ||
|
|
77c0e36ed6 | ||
|
|
694724d177 | ||
|
|
bf9cd4a12b | ||
|
|
f5aae7d214 | ||
|
|
bf61d12bfa | ||
|
|
7d9c5f9e2c | ||
|
|
b11c291df1 | ||
|
|
5a837226a4 | ||
|
|
ab76c66b68 | ||
|
|
f7c1340f99 | ||
|
|
2f045203ab | ||
|
|
842e239893 | ||
|
|
2e0d5eb829 | ||
|
|
56ebe688dc | ||
|
|
8b616e7d17 | ||
|
|
2ad823a79d | ||
|
|
94e1995469 | ||
|
|
f74ec03cef | ||
|
|
66e13d40f4 | ||
|
|
f60a9d7bd5 | ||
|
|
d47db903fb | ||
|
|
262972a911 | ||
|
|
fef97314cb | ||
|
|
069b9ce91d | ||
|
|
3e61aa7267 | ||
|
|
69614d6cf1 | ||
|
|
28352be729 | ||
|
|
549ef4b79d | ||
|
|
8fb95769bf | ||
|
|
7113875a45 | ||
|
|
8120023094 | ||
|
|
82d33332ab | ||
|
|
ecaa2e6a51 | ||
|
|
45ed3a4cff | ||
|
|
2b86647281 | ||
|
|
96ff387d1f | ||
|
|
565d6739b3 | ||
|
|
a53cbb677d | ||
|
|
afa6119ec1 | ||
|
|
175e430a2b | ||
|
|
6798d394bb | ||
|
|
7ff4306991 | ||
|
|
3d938b3450 | ||
|
|
8bf472e970 | ||
|
|
b75af8d9ff | ||
|
|
4308f7d09c | ||
|
|
89ce4ba632 | ||
|
|
fec8f08966 | ||
|
|
78b0e02ffe | ||
|
|
9e0f8100d9 | ||
|
|
08cd273be3 | ||
|
|
2a7dd8b8f1 | ||
|
|
b71a40ae6d | ||
|
|
87cc1d6217 | ||
|
|
577cb06371 | ||
|
|
361116a9ec | ||
|
|
cae8d566df | ||
|
|
f499cc375b | ||
|
|
338ba74652 | ||
|
|
5b3ff9160d | ||
|
|
deedafde9a | ||
|
|
d8b648d531 | ||
|
|
078d2bac11 | ||
|
|
e24a774d54 | ||
|
|
4d078feea2 | ||
|
|
f060da9c8d | ||
|
|
b2565991e6 | ||
|
|
eda0b16a5f | ||
|
|
e9a3f8ce91 | ||
|
|
a6bc9e66f6 | ||
|
|
b671543a95 | ||
|
|
4abc59f66d | ||
|
|
4aa2aa5aee | ||
|
|
2c5208ce6b | ||
|
|
81715aaf5d | ||
|
|
c4d47ccc20 | ||
|
|
694dd0c329 | ||
|
|
4884734ab5 | ||
|
|
28807d4f4d | ||
|
|
6a6f603754 | ||
|
|
2e3cb171a3 | ||
|
|
b853f908d3 | ||
|
|
1a40c83a48 | ||
|
|
9536b3e764 | ||
|
|
f1280a31a6 | ||
|
|
245c1eb305 | ||
|
|
bda1eafcec | ||
|
|
dd3101f27a | ||
|
|
45b0581b7b | ||
|
|
3234bc328f | ||
|
|
4defb38cf4 | ||
|
|
1150e69500 | ||
|
|
c7145f8dcd | ||
|
|
6fd9741daf | ||
|
|
a1d74649f3 | ||
|
|
f145db46f1 | ||
|
|
1b0000a1de | ||
|
|
8d01bb7ebf | ||
|
|
425105174e | ||
|
|
c5afd8cebf | ||
|
|
027189ac3c | ||
|
|
f0a3296e52 | ||
|
|
7db68795a4 | ||
|
|
2e8417d9e8 | ||
|
|
0e03b5f209 | ||
|
|
7e23479f3a | ||
|
|
a6480e6831 | ||
|
|
63e50dc88c | ||
|
|
fd7191f476 | ||
|
|
9343c3608b | ||
|
|
1577c01a77 | ||
|
|
46df14c0d9 | ||
|
|
e44fed2ff0 | ||
|
|
0d715ce615 | ||
|
|
96878f5dcb | ||
|
|
20cb11a298 | ||
|
|
0940af6b66 | ||
|
|
e0e8ba814f | ||
|
|
c59662758c | ||
|
|
c76a3815c0 | ||
|
|
1bdc55cb33 | ||
|
|
56f4d5af0f | ||
|
|
6e699b2e8b | ||
|
|
908c242d36 | ||
|
|
5e41865871 | ||
|
|
5dd9879b96 | ||
|
|
01c179856a | ||
|
|
9a6958573a | ||
|
|
a4e72f6fbc | ||
|
|
89a51bf1da | ||
|
|
d4318263f6 | ||
|
|
b8b19368df | ||
|
|
d5ea2a0206 | ||
|
|
9b275cc5f0 | ||
|
|
d1e3f74c03 | ||
|
|
fc3a132c12 | ||
|
|
31c4aad9e1 | ||
|
|
49c8e2f8cb | ||
|
|
83f9867632 | ||
|
|
65ac9d7226 | ||
|
|
e7b847542f | ||
|
|
20a94b4365 | ||
|
|
9b6db2bff4 | ||
|
|
6fc36a3e6c | ||
|
|
e476324c60 | ||
|
|
ec6805f573 | ||
|
|
7805d46743 | ||
|
|
881e82e825 | ||
|
|
2ae325455a | ||
|
|
922e335e83 | ||
|
|
cc6af82823 | ||
|
|
76e170eb3a | ||
|
|
c495e967cb | ||
|
|
017d6b1273 | ||
|
|
9eb770aed7 | ||
|
|
2f76a7ba80 | ||
|
|
58c39b340d | ||
|
|
f0c9e7cd44 | ||
|
|
f3fc70ebf0 | ||
|
|
884c111240 | ||
|
|
698126edb2 | ||
|
|
b3482a087b | ||
|
|
a552fb18da | ||
|
|
2670d2b0ad | ||
|
|
01063367c4 | ||
|
|
a0494b136f | ||
|
|
c088c47a49 | ||
|
|
77e354f9f6 | ||
|
|
dee471b1c7 | ||
|
|
bdd9e19efe | ||
|
|
34ceb9c226 | ||
|
|
bb24e1ce88 | ||
|
|
e75a964703 | ||
|
|
8805079faa | ||
|
|
7313aecd19 | ||
|
|
929839cb9f | ||
|
|
d707ba1a70 | ||
|
|
ff4f8f63af | ||
|
|
b3520c4385 | ||
|
|
526ab8b80f | ||
|
|
f29898886d | ||
|
|
1e84e4fa85 | ||
|
|
ce9b132ab5 | ||
|
|
5f4b2a752b | ||
|
|
4c1fc5671f | ||
|
|
e62e87549a | ||
|
|
62f7114fa1 | ||
|
|
47dc001735 | ||
|
|
3877bed62b | ||
|
|
ccdcf16cec | ||
|
|
54b138b2cc | ||
|
|
412bf8f638 | ||
|
|
b647f9382f | ||
|
|
56a9658b14 | ||
|
|
47991f192e | ||
|
|
4fde0ad2d7 | ||
|
|
1ec4f2e456 | ||
|
|
3a14a26bc6 | ||
|
|
fa41f6dc40 | ||
|
|
5497f229e1 | ||
|
|
206c8da0ba | ||
|
|
a2dff2305f | ||
|
|
726340fc86 | ||
|
|
823923f828 | ||
|
|
a49991c696 | ||
|
|
dc7c9ea272 | ||
|
|
58f13a3e06 | ||
|
|
5c0d846643 | ||
|
|
b821107c27 | ||
|
|
beb85e862a | ||
|
|
dee869a273 | ||
|
|
0c99007323 | ||
|
|
c91d707806 | ||
|
|
3adf571c1f | ||
|
|
c43b8abcbc | ||
|
|
3406f926fc | ||
|
|
e480d3a135 | ||
|
|
c1460afaee | ||
|
|
a73541da71 | ||
|
|
ceb978783c | ||
|
|
4b576d1590 | ||
|
|
04c5dff497 | ||
|
|
55f4415c0d | ||
|
|
6069127733 | ||
|
|
afd0f76d9e | ||
|
|
bab9123ca8 | ||
|
|
096324cf5e | ||
|
|
0e2774882f | ||
|
|
3775cd29cb | ||
|
|
a058af8211 | ||
|
|
139da3ac7a |
Binary file not shown.
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 162 KiB |
@@ -1,3 +1,3 @@
|
||||
angular.module("ofn.admin", ["ngResource", "ngAnimate", "ofn.dropdown", "admin.products", "infinite-scroll"]).config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.common["X-CSRF-Token"] = $("meta[name=csrf-token]").attr("content")
|
||||
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"
|
||||
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
//= require ./payment_methods/payment_methods
|
||||
//= require ./products/products
|
||||
//= require ./shipping_methods/shipping_methods
|
||||
//= require ./utils/utils
|
||||
//= require ./users/users
|
||||
//= require textAngular.min.js
|
||||
//= require textAngular-sanitize.min.js
|
||||
|
||||
//= require_tree .
|
||||
|
||||
@@ -43,6 +43,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", [
|
||||
$scope.currentFilters = []
|
||||
$scope.limit = 15
|
||||
$scope.productsWithUnsavedVariants = []
|
||||
$scope.query = ""
|
||||
|
||||
$scope.initialise = ->
|
||||
authorise_api_reponse = ""
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
angular.module("admin.enterprises")
|
||||
.controller "changeTypeFormCtrl", ($scope, enterprise) ->
|
||||
$scope.sells = enterprise.sells
|
||||
$scope.producer_profile_only = enterprise.producer_profile_only
|
||||
$scope.submitted = false
|
||||
|
||||
$scope.valid = (form) ->
|
||||
$scope.submitted = !form.$valid
|
||||
form.$valid
|
||||
|
||||
$scope.submit = (form) ->
|
||||
event.preventDefault() unless $scope.valid(form)
|
||||
@@ -1,8 +1,17 @@
|
||||
angular.module("admin.enterprises")
|
||||
.controller "enterpriseCtrl", ($scope, Enterprise, PaymentMethods, ShippingMethods) ->
|
||||
.controller "enterpriseCtrl", ($scope, longDescription, NavigationCheck, Enterprise, PaymentMethods, ShippingMethods) ->
|
||||
$scope.Enterprise = Enterprise.enterprise
|
||||
$scope.PaymentMethods = PaymentMethods.paymentMethods
|
||||
$scope.ShippingMethods = ShippingMethods.shippingMethods
|
||||
$scope.navClear = NavigationCheck.clear
|
||||
# htmlVariable is used by textAngular wysiwyg for the long descrtiption.
|
||||
$scope.htmlVariable = longDescription
|
||||
|
||||
# Provide a callback for generating warning messages displayed before leaving the page. This is passed in
|
||||
# from a directive "nav-check" in the page - if we pass it here it will be called in the test suite,
|
||||
# and on all new uses of this contoller, and we might not want that .
|
||||
$scope.enterpriseNavCallback = ->
|
||||
"You are editing an enterprise!"
|
||||
|
||||
for payment_method in $scope.PaymentMethods
|
||||
payment_method.selected = payment_method.id in $scope.Enterprise.payment_method_ids
|
||||
@@ -32,4 +41,4 @@ angular.module("admin.enterprises")
|
||||
$scope.ShippingMethods.reduce (count, shipping_method) ->
|
||||
count++ if shipping_method.selected
|
||||
count
|
||||
, 0
|
||||
, 0
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.enterprises", ["admin.payment_methods", "admin.shipping_methods", "admin.users"])
|
||||
angular.module("admin.enterprises", ["admin.payment_methods", "admin.utils", "admin.shipping_methods", "admin.users", "textAngular"])
|
||||
@@ -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,4 +1,4 @@
|
||||
angular.module('order_cycle', ['ngResource'])
|
||||
angular.module('admin.order_cycles', ['ngResource'])
|
||||
.controller('AdminCreateOrderCycleCtrl', ['$scope', 'OrderCycle', 'Enterprise', 'EnterpriseFee', ($scope, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
$scope.enterprises = Enterprise.index()
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
@@ -162,235 +162,6 @@ angular.module('order_cycle', ['ngResource'])
|
||||
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
|
||||
])
|
||||
|
||||
.factory('OrderCycle', ['$resource', '$window', ($resource, $window) ->
|
||||
OrderCycle = $resource '/admin/order_cycles/:order_cycle_id.json', {}, {
|
||||
'index': { method: 'GET', isArray: true}
|
||||
'create': { method: 'POST'}
|
||||
'update': { method: 'PUT'}}
|
||||
|
||||
{
|
||||
order_cycle:
|
||||
incoming_exchanges: []
|
||||
outgoing_exchanges: []
|
||||
coordinator_fees: []
|
||||
|
||||
loaded: false
|
||||
|
||||
exchangeSelectedVariants: (exchange) ->
|
||||
numActiveVariants = 0
|
||||
numActiveVariants++ for id, active of exchange.variants when active
|
||||
numActiveVariants
|
||||
|
||||
exchangeDirection: (exchange) ->
|
||||
if this.order_cycle.incoming_exchanges.indexOf(exchange) == -1 then 'outgoing' else 'incoming'
|
||||
|
||||
toggleProducts: (exchange) ->
|
||||
exchange.showProducts = !exchange.showProducts
|
||||
|
||||
setExchangeVariants: (exchange, variants, selected) ->
|
||||
exchange.variants[variant] = selected for variant in variants
|
||||
|
||||
addSupplier: (new_supplier_id) ->
|
||||
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
|
||||
|
||||
addDistributor: (new_distributor_id) ->
|
||||
this.order_cycle.outgoing_exchanges.push({enterprise_id: new_distributor_id, incoming: false, active: true, variants: {}, enterprise_fees: []})
|
||||
|
||||
removeExchange: (exchange) ->
|
||||
if exchange.incoming
|
||||
incoming_index = this.order_cycle.incoming_exchanges.indexOf exchange
|
||||
this.order_cycle.incoming_exchanges.splice(incoming_index, 1)
|
||||
this.removeDistributionOfVariant(variant_id) for variant_id, active of exchange.variants when active
|
||||
else
|
||||
outgoing_index = this.order_cycle.outgoing_exchanges.indexOf exchange
|
||||
this.order_cycle.outgoing_exchanges.splice(outgoing_index, 1) if outgoing_index > -1
|
||||
|
||||
addCoordinatorFee: ->
|
||||
this.order_cycle.coordinator_fees.push({})
|
||||
|
||||
removeCoordinatorFee: (index) ->
|
||||
this.order_cycle.coordinator_fees.splice(index, 1)
|
||||
|
||||
addExchangeFee: (exchange) ->
|
||||
exchange.enterprise_fees.push({})
|
||||
|
||||
removeExchangeFee: (exchange, index) ->
|
||||
exchange.enterprise_fees.splice(index, 1)
|
||||
|
||||
productSuppliedToOrderCycle: (product) ->
|
||||
product_variant_ids = (variant.id for variant in product.variants)
|
||||
variant_ids = [product.master_id].concat(product_variant_ids)
|
||||
incomingExchangesVariants = this.incomingExchangesVariants()
|
||||
|
||||
# TODO: This is an O(n^2) implementation of set intersection and thus is slooow.
|
||||
# Use a better algorithm if needed.
|
||||
# Also, incomingExchangesVariants is called every time, when it only needs to be
|
||||
# called once per change to incoming variants. Some sort of caching?
|
||||
ids = (variant_id for variant_id in variant_ids when incomingExchangesVariants.indexOf(variant_id) != -1)
|
||||
ids.length > 0
|
||||
|
||||
variantSuppliedToOrderCycle: (variant) ->
|
||||
this.incomingExchangesVariants().indexOf(variant.id) != -1
|
||||
|
||||
incomingExchangesVariants: ->
|
||||
variant_ids = []
|
||||
|
||||
for exchange in this.order_cycle.incoming_exchanges
|
||||
variant_ids.push(parseInt(id)) for id, active of exchange.variants when active
|
||||
variant_ids
|
||||
|
||||
participatingEnterpriseIds: ->
|
||||
suppliers = (exchange.enterprise_id for exchange in this.order_cycle.incoming_exchanges)
|
||||
distributors = (exchange.enterprise_id for exchange in this.order_cycle.outgoing_exchanges)
|
||||
jQuery.unique(suppliers.concat(distributors)).sort()
|
||||
|
||||
removeDistributionOfVariant: (variant_id) ->
|
||||
for exchange in this.order_cycle.outgoing_exchanges
|
||||
exchange.variants[variant_id] = false
|
||||
|
||||
load: (order_cycle_id) ->
|
||||
service = this
|
||||
OrderCycle.get {order_cycle_id: order_cycle_id}, (oc) ->
|
||||
angular.extend(service.order_cycle, oc)
|
||||
service.order_cycle.incoming_exchanges = []
|
||||
service.order_cycle.outgoing_exchanges = []
|
||||
for exchange in service.order_cycle.exchanges
|
||||
if exchange.incoming
|
||||
angular.extend(exchange, {enterprise_id: exchange.sender_id, active: true})
|
||||
delete(exchange.receiver_id)
|
||||
service.order_cycle.incoming_exchanges.push(exchange)
|
||||
|
||||
else
|
||||
angular.extend(exchange, {enterprise_id: exchange.receiver_id, active: true})
|
||||
delete(exchange.sender_id)
|
||||
service.order_cycle.outgoing_exchanges.push(exchange)
|
||||
|
||||
delete(service.order_cycle.exchanges)
|
||||
service.loaded = true
|
||||
|
||||
this.order_cycle
|
||||
|
||||
create: ->
|
||||
oc = new OrderCycle({order_cycle: this.dataForSubmit()})
|
||||
oc.$create (data) ->
|
||||
if data['success']
|
||||
$window.location = '/admin/order_cycles'
|
||||
else
|
||||
console.log('Failed to create order cycle')
|
||||
|
||||
update: ->
|
||||
oc = new OrderCycle({order_cycle: this.dataForSubmit()})
|
||||
oc.$update {order_cycle_id: this.order_cycle.id}, (data) ->
|
||||
if data['success']
|
||||
$window.location = '/admin/order_cycles'
|
||||
else
|
||||
console.log('Failed to update order cycle')
|
||||
|
||||
dataForSubmit: ->
|
||||
data = this.deepCopy()
|
||||
data = this.removeInactiveExchanges(data)
|
||||
data = this.translateCoordinatorFees(data)
|
||||
data = this.translateExchangeFees(data)
|
||||
data
|
||||
|
||||
deepCopy: ->
|
||||
data = angular.extend({}, this.order_cycle)
|
||||
|
||||
# Copy exchanges
|
||||
data.incoming_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.incoming_exchanges) if this.order_cycle.incoming_exchanges?
|
||||
data.outgoing_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.outgoing_exchanges) if this.order_cycle.outgoing_exchanges?
|
||||
|
||||
# Copy exchange fees
|
||||
all_exchanges = (data.incoming_exchanges || []) + (data.outgoing_exchanges || [])
|
||||
for exchange in all_exchanges
|
||||
if exchange.enterprise_fees?
|
||||
exchange.enterprise_fees = (angular.extend {}, fee for fee in exchange.enterprise_fees)
|
||||
|
||||
data
|
||||
|
||||
removeInactiveExchanges: (order_cycle) ->
|
||||
order_cycle.incoming_exchanges =
|
||||
(exchange for exchange in order_cycle.incoming_exchanges when exchange.active)
|
||||
order_cycle.outgoing_exchanges =
|
||||
(exchange for exchange in order_cycle.outgoing_exchanges when exchange.active)
|
||||
order_cycle
|
||||
|
||||
translateCoordinatorFees: (order_cycle) ->
|
||||
order_cycle.coordinator_fee_ids = (fee.id for fee in order_cycle.coordinator_fees)
|
||||
delete order_cycle.coordinator_fees
|
||||
order_cycle
|
||||
|
||||
translateExchangeFees: (order_cycle) ->
|
||||
for exchange in order_cycle.incoming_exchanges
|
||||
exchange.enterprise_fee_ids = (fee.id for fee in exchange.enterprise_fees)
|
||||
delete exchange.enterprise_fees
|
||||
for exchange in order_cycle.outgoing_exchanges
|
||||
exchange.enterprise_fee_ids = (fee.id for fee in exchange.enterprise_fees)
|
||||
delete exchange.enterprise_fees
|
||||
order_cycle
|
||||
}])
|
||||
|
||||
.factory('Enterprise', ['$resource', ($resource) ->
|
||||
Enterprise = $resource('/admin/enterprises/for_order_cycle/:enterprise_id.json', {}, {'index': {method: 'GET', isArray: true}})
|
||||
|
||||
{
|
||||
Enterprise: Enterprise
|
||||
enterprises: {}
|
||||
supplied_products: []
|
||||
loaded: false
|
||||
|
||||
index: ->
|
||||
service = this
|
||||
|
||||
Enterprise.index (data) ->
|
||||
for enterprise in data
|
||||
service.enterprises[enterprise.id] = enterprise
|
||||
|
||||
for product in enterprise.supplied_products
|
||||
service.supplied_products.push(product)
|
||||
|
||||
service.loaded = true
|
||||
|
||||
this.enterprises
|
||||
|
||||
suppliedVariants: (enterprise_id) ->
|
||||
vs = (this.variantsOf(product) for product in this.enterprises[enterprise_id].supplied_products)
|
||||
[].concat vs...
|
||||
|
||||
variantsOf: (product) ->
|
||||
if product.variants.length > 0
|
||||
variant.id for variant in product.variants
|
||||
else
|
||||
[product.master_id]
|
||||
|
||||
totalVariants: (enterprise) ->
|
||||
numVariants = 0
|
||||
|
||||
if enterprise
|
||||
counts = for product in enterprise.supplied_products
|
||||
numVariants += if product.variants.length == 0 then 1 else product.variants.length
|
||||
|
||||
numVariants
|
||||
}])
|
||||
|
||||
.factory('EnterpriseFee', ['$resource', ($resource) ->
|
||||
EnterpriseFee = $resource('/admin/enterprise_fees/:enterprise_fee_id.json', {}, {'index': {method: 'GET', isArray: true}})
|
||||
|
||||
{
|
||||
EnterpriseFee: EnterpriseFee
|
||||
enterprise_fees: {}
|
||||
loaded: false
|
||||
|
||||
index: ->
|
||||
service = this
|
||||
EnterpriseFee.index (data) ->
|
||||
service.enterprise_fees = data
|
||||
service.loaded = true
|
||||
|
||||
forEnterprise: (enterprise_id) ->
|
||||
enterprise_fee for enterprise_fee in this.enterprise_fees when enterprise_fee.enterprise_id == enterprise_id
|
||||
}])
|
||||
|
||||
.directive('datetimepicker', ['$parse', ($parse) ->
|
||||
(scope, element, attrs) ->
|
||||
# using $parse instead of scope[attrs.datetimepicker] for cases
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
$scope.enterprises = Enterprise.index (enterprises) =>
|
||||
$scope.init(enterprises)
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
|
||||
$scope.init = (enterprises) ->
|
||||
enterprise = enterprises[Object.keys(enterprises)[0]]
|
||||
OrderCycle.addSupplier enterprise.id
|
||||
OrderCycle.addDistributor enterprise.id
|
||||
$scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0]
|
||||
|
||||
# All variants start as checked
|
||||
OrderCycle.setExchangeVariants(OrderCycle.order_cycle.incoming_exchanges[0],
|
||||
Enterprise.suppliedVariants(enterprise.id), true)
|
||||
|
||||
OrderCycle.order_cycle.coordinator_id = enterprise.id
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded
|
||||
|
||||
$scope.removeDistributionOfVariant = angular.noop
|
||||
|
||||
$scope.setExchangeVariants = (exchange, variants, selected) ->
|
||||
OrderCycle.setExchangeVariants(exchange, variants, selected)
|
||||
|
||||
$scope.suppliedVariants = (enterprise_id) ->
|
||||
Enterprise.suppliedVariants(enterprise_id)
|
||||
|
||||
$scope.addCoordinatorFee = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addCoordinatorFee()
|
||||
|
||||
$scope.removeCoordinatorFee = ($event, index) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.removeCoordinatorFee(index)
|
||||
|
||||
$scope.enterpriseFeesForEnterprise = (enterprise_id) ->
|
||||
EnterpriseFee.forEnterprise(parseInt(enterprise_id))
|
||||
|
||||
$scope.submit = ->
|
||||
OrderCycle.mirrorIncomingToOutgoingProducts()
|
||||
OrderCycle.create()
|
||||
@@ -0,0 +1,37 @@
|
||||
angular.module('admin.order_cycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $location, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
$scope.orderCycleId = ->
|
||||
$location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
|
||||
$scope.enterprises = Enterprise.index()
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
$scope.order_cycle = OrderCycle.load $scope.orderCycleId(), (order_cycle) =>
|
||||
$scope.init()
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
|
||||
$scope.init = ->
|
||||
$scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0]
|
||||
|
||||
$scope.enterpriseFeesForEnterprise = (enterprise_id) ->
|
||||
EnterpriseFee.forEnterprise(parseInt(enterprise_id))
|
||||
|
||||
$scope.removeDistributionOfVariant = angular.noop
|
||||
|
||||
$scope.setExchangeVariants = (exchange, variants, selected) ->
|
||||
OrderCycle.setExchangeVariants(exchange, variants, selected)
|
||||
|
||||
$scope.suppliedVariants = (enterprise_id) ->
|
||||
Enterprise.suppliedVariants(enterprise_id)
|
||||
|
||||
$scope.addCoordinatorFee = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addCoordinatorFee()
|
||||
|
||||
$scope.removeCoordinatorFee = ($event, index) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.removeCoordinatorFee(index)
|
||||
|
||||
$scope.submit = ->
|
||||
OrderCycle.mirrorIncomingToOutgoingProducts()
|
||||
OrderCycle.update()
|
||||
@@ -0,0 +1,43 @@
|
||||
angular.module('admin.order_cycles').factory('Enterprise', ($resource) ->
|
||||
Enterprise = $resource('/admin/enterprises/for_order_cycle/:enterprise_id.json', {}, {'index': {method: 'GET', isArray: true}})
|
||||
|
||||
{
|
||||
Enterprise: Enterprise
|
||||
enterprises: {}
|
||||
supplied_products: []
|
||||
loaded: false
|
||||
|
||||
index: (callback=null) ->
|
||||
service = this
|
||||
|
||||
Enterprise.index (data) ->
|
||||
for enterprise in data
|
||||
service.enterprises[enterprise.id] = enterprise
|
||||
|
||||
for product in enterprise.supplied_products
|
||||
service.supplied_products.push(product)
|
||||
|
||||
service.loaded = true
|
||||
(callback || angular.noop)(service.enterprises)
|
||||
|
||||
this.enterprises
|
||||
|
||||
suppliedVariants: (enterprise_id) ->
|
||||
vs = (this.variantsOf(product) for product in this.enterprises[enterprise_id].supplied_products)
|
||||
[].concat vs...
|
||||
|
||||
variantsOf: (product) ->
|
||||
if product.variants.length > 0
|
||||
variant.id for variant in product.variants
|
||||
else
|
||||
[product.master_id]
|
||||
|
||||
totalVariants: (enterprise) ->
|
||||
numVariants = 0
|
||||
|
||||
if enterprise
|
||||
counts = for product in enterprise.supplied_products
|
||||
numVariants += if product.variants.length == 0 then 1 else product.variants.length
|
||||
|
||||
numVariants
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
angular.module('admin.order_cycles').factory('EnterpriseFee', ($resource) ->
|
||||
EnterpriseFee = $resource('/admin/enterprise_fees/:enterprise_fee_id.json', {}, {'index': {method: 'GET', isArray: true}})
|
||||
|
||||
{
|
||||
EnterpriseFee: EnterpriseFee
|
||||
enterprise_fees: {}
|
||||
loaded: false
|
||||
|
||||
index: ->
|
||||
service = this
|
||||
EnterpriseFee.index (data) ->
|
||||
service.enterprise_fees = data
|
||||
service.loaded = true
|
||||
|
||||
forEnterprise: (enterprise_id) ->
|
||||
enterprise_fee for enterprise_fee in this.enterprise_fees when enterprise_fee.enterprise_id == enterprise_id
|
||||
})
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window) ->
|
||||
OrderCycle = $resource '/admin/order_cycles/:order_cycle_id.json', {}, {
|
||||
'index': { method: 'GET', isArray: true}
|
||||
'create': { method: 'POST'}
|
||||
'update': { method: 'PUT'}}
|
||||
|
||||
{
|
||||
order_cycle:
|
||||
incoming_exchanges: []
|
||||
outgoing_exchanges: []
|
||||
coordinator_fees: []
|
||||
|
||||
loaded: false
|
||||
|
||||
exchangeSelectedVariants: (exchange) ->
|
||||
numActiveVariants = 0
|
||||
numActiveVariants++ for id, active of exchange.variants when active
|
||||
numActiveVariants
|
||||
|
||||
exchangeDirection: (exchange) ->
|
||||
if this.order_cycle.incoming_exchanges.indexOf(exchange) == -1 then 'outgoing' else 'incoming'
|
||||
|
||||
toggleProducts: (exchange) ->
|
||||
exchange.showProducts = !exchange.showProducts
|
||||
|
||||
setExchangeVariants: (exchange, variants, selected) ->
|
||||
exchange.variants[variant] = selected for variant in variants
|
||||
|
||||
addSupplier: (new_supplier_id) ->
|
||||
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
|
||||
|
||||
addDistributor: (new_distributor_id) ->
|
||||
this.order_cycle.outgoing_exchanges.push({enterprise_id: new_distributor_id, incoming: false, active: true, variants: {}, enterprise_fees: []})
|
||||
|
||||
removeExchange: (exchange) ->
|
||||
if exchange.incoming
|
||||
incoming_index = this.order_cycle.incoming_exchanges.indexOf exchange
|
||||
this.order_cycle.incoming_exchanges.splice(incoming_index, 1)
|
||||
this.removeDistributionOfVariant(variant_id) for variant_id, active of exchange.variants when active
|
||||
else
|
||||
outgoing_index = this.order_cycle.outgoing_exchanges.indexOf exchange
|
||||
this.order_cycle.outgoing_exchanges.splice(outgoing_index, 1) if outgoing_index > -1
|
||||
|
||||
addCoordinatorFee: ->
|
||||
this.order_cycle.coordinator_fees.push({})
|
||||
|
||||
removeCoordinatorFee: (index) ->
|
||||
this.order_cycle.coordinator_fees.splice(index, 1)
|
||||
|
||||
addExchangeFee: (exchange) ->
|
||||
exchange.enterprise_fees.push({})
|
||||
|
||||
removeExchangeFee: (exchange, index) ->
|
||||
exchange.enterprise_fees.splice(index, 1)
|
||||
|
||||
productSuppliedToOrderCycle: (product) ->
|
||||
product_variant_ids = (variant.id for variant in product.variants)
|
||||
variant_ids = [product.master_id].concat(product_variant_ids)
|
||||
incomingExchangesVariants = this.incomingExchangesVariants()
|
||||
|
||||
# TODO: This is an O(n^2) implementation of set intersection and thus is slooow.
|
||||
# Use a better algorithm if needed.
|
||||
# Also, incomingExchangesVariants is called every time, when it only needs to be
|
||||
# called once per change to incoming variants. Some sort of caching?
|
||||
ids = (variant_id for variant_id in variant_ids when incomingExchangesVariants.indexOf(variant_id) != -1)
|
||||
ids.length > 0
|
||||
|
||||
variantSuppliedToOrderCycle: (variant) ->
|
||||
this.incomingExchangesVariants().indexOf(variant.id) != -1
|
||||
|
||||
incomingExchangesVariants: ->
|
||||
variant_ids = []
|
||||
|
||||
for exchange in this.order_cycle.incoming_exchanges
|
||||
variant_ids.push(parseInt(id)) for id, active of exchange.variants when active
|
||||
variant_ids
|
||||
|
||||
participatingEnterpriseIds: ->
|
||||
suppliers = (exchange.enterprise_id for exchange in this.order_cycle.incoming_exchanges)
|
||||
distributors = (exchange.enterprise_id for exchange in this.order_cycle.outgoing_exchanges)
|
||||
jQuery.unique(suppliers.concat(distributors)).sort()
|
||||
|
||||
removeDistributionOfVariant: (variant_id) ->
|
||||
for exchange in this.order_cycle.outgoing_exchanges
|
||||
exchange.variants[variant_id] = false
|
||||
|
||||
load: (order_cycle_id, callback=null) ->
|
||||
service = this
|
||||
OrderCycle.get {order_cycle_id: order_cycle_id}, (oc) ->
|
||||
angular.extend(service.order_cycle, oc)
|
||||
service.order_cycle.incoming_exchanges = []
|
||||
service.order_cycle.outgoing_exchanges = []
|
||||
for exchange in service.order_cycle.exchanges
|
||||
if exchange.incoming
|
||||
angular.extend(exchange, {enterprise_id: exchange.sender_id, active: true})
|
||||
delete(exchange.receiver_id)
|
||||
service.order_cycle.incoming_exchanges.push(exchange)
|
||||
|
||||
else
|
||||
angular.extend(exchange, {enterprise_id: exchange.receiver_id, active: true})
|
||||
delete(exchange.sender_id)
|
||||
service.order_cycle.outgoing_exchanges.push(exchange)
|
||||
|
||||
delete(service.order_cycle.exchanges)
|
||||
service.loaded = true
|
||||
|
||||
(callback || angular.noop)(service.order_cycle)
|
||||
|
||||
this.order_cycle
|
||||
|
||||
create: ->
|
||||
oc = new OrderCycle({order_cycle: this.dataForSubmit()})
|
||||
oc.$create (data) ->
|
||||
if data['success']
|
||||
$window.location = '/admin/order_cycles'
|
||||
else
|
||||
console.log('Failed to create order cycle')
|
||||
|
||||
update: ->
|
||||
oc = new OrderCycle({order_cycle: this.dataForSubmit()})
|
||||
oc.$update {order_cycle_id: this.order_cycle.id}, (data) ->
|
||||
if data['success']
|
||||
$window.location = '/admin/order_cycles'
|
||||
else
|
||||
console.log('Failed to update order cycle')
|
||||
|
||||
dataForSubmit: ->
|
||||
data = this.deepCopy()
|
||||
data = this.removeInactiveExchanges(data)
|
||||
data = this.translateCoordinatorFees(data)
|
||||
data = this.translateExchangeFees(data)
|
||||
data
|
||||
|
||||
deepCopy: ->
|
||||
data = angular.extend({}, this.order_cycle)
|
||||
|
||||
# Copy exchanges
|
||||
data.incoming_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.incoming_exchanges) if this.order_cycle.incoming_exchanges?
|
||||
data.outgoing_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.outgoing_exchanges) if this.order_cycle.outgoing_exchanges?
|
||||
|
||||
# Copy exchange fees
|
||||
all_exchanges = (data.incoming_exchanges || []) + (data.outgoing_exchanges || [])
|
||||
for exchange in all_exchanges
|
||||
if exchange.enterprise_fees?
|
||||
exchange.enterprise_fees = (angular.extend {}, fee for fee in exchange.enterprise_fees)
|
||||
|
||||
data
|
||||
|
||||
removeInactiveExchanges: (order_cycle) ->
|
||||
order_cycle.incoming_exchanges =
|
||||
(exchange for exchange in order_cycle.incoming_exchanges when exchange.active)
|
||||
order_cycle.outgoing_exchanges =
|
||||
(exchange for exchange in order_cycle.outgoing_exchanges when exchange.active)
|
||||
order_cycle
|
||||
|
||||
translateCoordinatorFees: (order_cycle) ->
|
||||
order_cycle.coordinator_fee_ids = (fee.id for fee in order_cycle.coordinator_fees)
|
||||
delete order_cycle.coordinator_fees
|
||||
order_cycle
|
||||
|
||||
translateExchangeFees: (order_cycle) ->
|
||||
for exchange in order_cycle.incoming_exchanges
|
||||
exchange.enterprise_fee_ids = (fee.id for fee in exchange.enterprise_fees)
|
||||
delete exchange.enterprise_fees
|
||||
for exchange in order_cycle.outgoing_exchanges
|
||||
exchange.enterprise_fee_ids = (fee.id for fee in exchange.enterprise_fees)
|
||||
delete exchange.enterprise_fees
|
||||
order_cycle
|
||||
|
||||
# In the simple UI, we don't list outgoing products. Instead, all products are considered
|
||||
# part of both incoming and outgoing enterprises. This method mirrors the former to the
|
||||
# latter **for order cycles with a single incoming and outgoing exchange only**.
|
||||
mirrorIncomingToOutgoingProducts: ->
|
||||
incoming = this.order_cycle.incoming_exchanges[0]
|
||||
outgoing = this.order_cycle.outgoing_exchanges[0]
|
||||
|
||||
for id, active of incoming.variants
|
||||
outgoing.variants[id] = active
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
angular.module("admin.utils").directive "navCheck", (NavigationCheck)->
|
||||
restrict: 'A'
|
||||
scope:
|
||||
navCallback: '&'
|
||||
link: (scope,element,attributes) ->
|
||||
# Define navigationCallback on a controller in scope, otherwise this default will be used:
|
||||
scope.navCallback ||= ->
|
||||
"You will lose any unsaved work!"
|
||||
NavigationCheck.register(scope.navCallback)
|
||||
@@ -0,0 +1,46 @@
|
||||
angular.module("admin.utils")
|
||||
.factory "NavigationCheck", ($window, $rootScope) ->
|
||||
new class NavigationCheck
|
||||
callbacks = []
|
||||
constructor: ->
|
||||
if $window.addEventListener
|
||||
$window.addEventListener "beforeunload", @onBeforeUnloadHandler
|
||||
else
|
||||
$window.onbeforeunload = @onBeforeUnloadHandler
|
||||
|
||||
$rootScope.$on "$locationChangeStart", @locationChangeStartHandler
|
||||
|
||||
|
||||
# Action for regular browser navigation.
|
||||
onBeforeUnloadHandler: ($event) =>
|
||||
message = @getMessage()
|
||||
if message
|
||||
($event or $window.event).preventDefault()
|
||||
message
|
||||
|
||||
# Action for angular navigation.
|
||||
locationChangeStartHandler: ($event) =>
|
||||
message = @getMessage()
|
||||
if message and not $window.confirm(message)
|
||||
$event.stopPropagation() if $event.stopPropagation
|
||||
$event.preventDefault() if $event.preventDefault
|
||||
$event.cancelBubble = true
|
||||
$event.returnValue = false
|
||||
|
||||
# Runs callback functions to retreive most recently added non-empty message.
|
||||
getMessage: ->
|
||||
message = null
|
||||
message = callback() ? message for callback in callbacks
|
||||
message
|
||||
|
||||
register: (callback) =>
|
||||
callbacks.push callback
|
||||
|
||||
clear: =>
|
||||
if $window.addEventListener
|
||||
$window.removeEventListener "beforeunload", @onBeforeUnloadHandler
|
||||
else
|
||||
$window.onbeforeunload = null
|
||||
|
||||
$rootScope.$on "$locationChangeStart", null
|
||||
|
||||
1
app/assets/javascripts/admin/utils/utils.js.coffee
Normal file
1
app/assets/javascripts/admin/utils/utils.js.coffee
Normal file
@@ -0,0 +1 @@
|
||||
angular.module("admin.utils", [])
|
||||
@@ -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
|
||||
@@ -3,7 +3,7 @@ Darkswarm.controller "RegistrationCtrl", ($scope, RegistrationService, Enterpris
|
||||
$scope.enterprise = EnterpriseRegistrationService.enterprise
|
||||
$scope.select = RegistrationService.select
|
||||
|
||||
$scope.steps = ['details','address','contact','about','images','social']
|
||||
$scope.steps = ['details','contact','type','about','images','social']
|
||||
|
||||
$scope.countries = availableCountries
|
||||
|
||||
@@ -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)
|
||||
@@ -0,0 +1,7 @@
|
||||
Darkswarm.directive "ofnInlineAlert", ->
|
||||
restrict: 'A'
|
||||
scope: true
|
||||
link: (scope, elem, attrs) ->
|
||||
scope.visible = true
|
||||
scope.close = ->
|
||||
scope.visible = false
|
||||
@@ -1,6 +0,0 @@
|
||||
Darkswarm.directive "ofnInlineFlash", ->
|
||||
restrict: 'E'
|
||||
controller: ($scope) ->
|
||||
$scope.visible = true
|
||||
$scope.closeFlash = ->
|
||||
$scope.visible = false
|
||||
@@ -3,7 +3,7 @@ Darkswarm.directive "ofnRegistrationLimitModal", (Navigation, $modal, Loading) -
|
||||
link: (scope, elem, attr)->
|
||||
scope.modalInstance = $modal.open
|
||||
templateUrl: 'registration/limit_reached.html'
|
||||
windowClass: "login-modal large"
|
||||
windowClass: "login-modal register-modal xlarge"
|
||||
backdrop: 'static'
|
||||
|
||||
scope.modalInstance.result.then scope.close, scope.close
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redirections)->
|
||||
Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redirections, Loading)->
|
||||
|
||||
new class AuthenticationService
|
||||
selectedPath: "/login"
|
||||
@@ -25,4 +25,9 @@ Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redir
|
||||
active: Navigation.active
|
||||
|
||||
close: ->
|
||||
Navigation.navigate "/"
|
||||
if location.pathname == "/"
|
||||
Navigation.navigate "/"
|
||||
else
|
||||
Loading.message = "Taking you back to the home page"
|
||||
location.hash = ""
|
||||
location.pathname = "/"
|
||||
|
||||
@@ -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,44 +1,47 @@
|
||||
.container#registration-about
|
||||
.header
|
||||
%h2 Nice one!
|
||||
%h5
|
||||
Now let's flesh out the details about
|
||||
%span.brick{"ng-show" => "enterprise.is_distributor"}
|
||||
{{ enterprise.name }}
|
||||
%span.turquoise{"ng-show" => "!enterprise.is_distributor" }
|
||||
{{ enterprise.name }}
|
||||
|
||||
%ng-include{ src: "'registration/steps.html'" }
|
||||
.row
|
||||
.small-12.columns
|
||||
%header
|
||||
%h2 Nice one!
|
||||
%h5
|
||||
Now let's flesh out the details about
|
||||
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
|
||||
{{ enterprise.name }}
|
||||
|
||||
%form{ name: 'about', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('images',about)" } }
|
||||
.row
|
||||
.small-12.columns
|
||||
.alert-box.alert{"data-alert" => ""}
|
||||
{{ enterprise.name }} won't be visible on the Open Food Network until you enter a long and short description.
|
||||
%a.close{:href => "#"} ×
|
||||
|
||||
.alert-box.info{"data-alert" => ""}
|
||||
{{ enterprise.name }} has been created on the Open Food Network. If you leave at any point from here onwards, your enterprise will be saved, and you can always login to the admin section to update or continue filling out your enterprise details.
|
||||
%a.close{:href => "#"} ×
|
||||
.alert-box.info{ "ofn-inline-alert" => true, ng: { show: "visible" } }
|
||||
%h6 Success! {{ enterprise.name }} added to the Open Food Network
|
||||
%span If you exit the wizard at any stage, login and go to admin to edit or update your enterprise details.
|
||||
%a.close{ ng: { click: "close()" } } ×
|
||||
|
||||
.small-12.large-8.columns
|
||||
.row
|
||||
.small-12.columns
|
||||
%label{ for: 'enterprise_description' } Short Description:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_description', placeholder: "A short sentence describing your enterprise", ng: { model: 'enterprise.description' } }
|
||||
.field
|
||||
%label{ for: 'enterprise_description' } Short Description:
|
||||
%input.chunky{ id: 'enterprise_description', placeholder: "A short sentence describing your enterprise", ng: { model: 'enterprise.description' } }
|
||||
.row
|
||||
.small-12.columns
|
||||
%label{ for: 'enterprise_long_desc' } Long Description:
|
||||
%textarea.chunky.small-12.columns{ id: 'enterprise_long_desc', rows: 6, placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words.", ng: { model: 'enterprise.long_description' } }
|
||||
%small {{ enterprise.long_description.length }} characters / up to 600 recommended
|
||||
.field
|
||||
%label{ for: 'enterprise_long_desc' } Long Description:
|
||||
%textarea.chunky{ id: 'enterprise_long_desc', rows: 6, placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words.", ng: { model: 'enterprise.long_description' } }
|
||||
%small {{ enterprise.long_description.length }} characters / up to 600 recommended
|
||||
.small-12.large-4.columns
|
||||
.row
|
||||
.small-12.columns
|
||||
%label{ for: 'enterprise_abn' } ABN:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_abn', placeholder: "eg. 99 123 456 789", ng: { model: 'enterprise.abn' } }
|
||||
.field
|
||||
%label{ for: 'enterprise_abn' } ABN:
|
||||
%input.chunky{ id: 'enterprise_abn', placeholder: "eg. 99 123 456 789", ng: { model: 'enterprise.abn' } }
|
||||
.row
|
||||
.small-12.columns
|
||||
%label{ for: 'enterprise_acn' } ACN:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_acn', placeholder: "eg. 123 456 789", ng: { model: 'enterprise.acn' } }
|
||||
.field
|
||||
%label{ for: 'enterprise_acn' } ACN:
|
||||
%input.chunky{ id: 'enterprise_acn', placeholder: "eg. 123 456 789", ng: { model: 'enterprise.acn' } }
|
||||
|
||||
.row.buttons.pad-top
|
||||
.small-12.columns
|
||||
%input.button.primary{ type: "submit", value: "Continue" }
|
||||
%input.button.primary.right{ type: "submit", value: "Continue" }
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
.container#registration-address
|
||||
.header
|
||||
%h2
|
||||
Greetings
|
||||
%span{ ng: { class: "{brick: enterprise.is_distributor, turquoise: !enterprise.is_distributor}" } }
|
||||
{{ enterprise.name }}
|
||||
|
||||
%h5 Now we need to know where you are
|
||||
%ng-include{ src: "'registration/steps.html'" }
|
||||
%form{ name: 'address', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('contact',address)" } }
|
||||
.row.content
|
||||
.small-12.medium-12.large-7.columns
|
||||
.row
|
||||
.small-12.columns.field
|
||||
%label{ for: 'enterprise_address' } Address:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_address', name: 'address1', required: true, placeholder: "eg. 123 Cranberry Drive", required: true, ng: { model: 'enterprise.address.address1' } }
|
||||
%span.error.small-12.columns{ ng: { show: "address.address1.$error.required && submitted" } }
|
||||
You need to enter an address.
|
||||
.row
|
||||
.small-12.large-8.columns.field
|
||||
%label{ for: 'enterprise_city' } Suburb:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_city', name: 'city', required: true, placeholder: "eg. Northcote", ng: { model: 'enterprise.address.city' } }
|
||||
%span.error.small-12.columns{ ng: { show: "address.city.$error.required && submitted" } }
|
||||
You need to enter a suburb.
|
||||
.small-12.large-4.columns.field
|
||||
%label{ for: 'enterprise_zipcode' } Postcode:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_zipcode', name: 'zipcode', required: true, placeholder: "eg. 3070", ng: { model: 'enterprise.address.zipcode' } }
|
||||
%span.error.small-12.columns{ ng: { show: "address.zipcode.$error.required && submitted" } }
|
||||
You need to enter a postcode.
|
||||
.row
|
||||
.small-12.large-8.columns.field
|
||||
%label{ for: 'enterprise_country' } Country:
|
||||
%select.chunky.small-12.columns{ id: 'enterprise_country', name: 'country', required: true, ng: { model: 'enterprise.country', options: 'c as c.name for c in countries' } }
|
||||
%span.error.small-12.columns{ ng: { show: "address.country.$error.required && submitted" } }
|
||||
You need to enter a country.
|
||||
.small-12.large-4.columns.field
|
||||
%label{ for: 'enterprise_state' } State:
|
||||
%select.chunky.small-12.columns{ id: 'enterprise_state', name: 'state', ng: { model: 'enterprise.address.state_id', options: 's.id as s.abbr for s in enterprise.country.states', show: 'countryHasStates()', required: 'countryHasStates()' } }
|
||||
%span.error.small-12.columns{ ng: { show: "address.state.$error.required && submitted" } }
|
||||
You need to enter a state.
|
||||
.small-12.medium-12.large-5.hide-for-small-only
|
||||
// This is the location area
|
||||
/ %h6
|
||||
/ Location display
|
||||
/ %i.ofn-i_013-help.has-tip{ 'data-tooltip' => true, title: "Choose how you want to display your enterprise's address on the Open Food Network. By default, full location is shown everywhere including street name and number."}
|
||||
/ .row
|
||||
/ .small-12.columns
|
||||
/ %label.indent-checkbox
|
||||
/ %input{ type: 'checkbox', id: 'enterpise_suburb_only', ng: { model: 'enterprise.suburb_only' } }
|
||||
/ Hide my street name and street number from the public (ie. only show the suburb)
|
||||
/ .small-12.columns
|
||||
/ %label.indent-checkbox
|
||||
/ %input{ type: 'checkbox', id: 'enterprise_on_map', ng: { model: 'enterprise.on_map' } }
|
||||
/ Blur my location on the map (show an approximate, not exact pin)
|
||||
|
||||
.row.buttons
|
||||
.small-12.columns
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('details')" } }
|
||||
|
||||
%input.button.primary{ type: "submit", value: "Continue" }
|
||||
@@ -1,12 +1,13 @@
|
||||
.container#registration-contact
|
||||
.header
|
||||
%h2 Last step to create your enterprise!
|
||||
%h5
|
||||
Who is responsible for managing
|
||||
%span{ ng: { class: "{brick: enterprise.is_distributor, turquoise: !enterprise.is_distributor}" } }
|
||||
{{ enterprise.name }}?
|
||||
%ng-include{ src: "'registration/steps.html'" }
|
||||
%form{ name: 'contact', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "create(contact)" } }
|
||||
.row
|
||||
.small-12.columns
|
||||
%header
|
||||
%h2 Greetings!
|
||||
%h5
|
||||
Who is responsible for managing {{ enterprise.name }}?
|
||||
|
||||
%form{ name: 'contact', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('type',contact)" } }
|
||||
.row.content
|
||||
.small-12.medium-12.large-7.columns
|
||||
.row
|
||||
@@ -39,8 +40,8 @@
|
||||
/ .small-12.columns
|
||||
/ %label.indent-checkbox
|
||||
/ %input{ type: 'checkbox', id: 'contact_phone_profile', ng: { model: 'enterprise.phone_in_profile' } } Display phone in profile
|
||||
|
||||
.row.buttons
|
||||
.small-12.columns
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('address')" } }
|
||||
|
||||
%input.button.primary{ type: "submit", value: "Continue" }
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('details')" } }
|
||||
%input.button.primary.right{ type: "submit", value: "Continue" }
|
||||
|
||||
@@ -1,42 +1,77 @@
|
||||
.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:
|
||||
%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:
|
||||
%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
|
||||
.small-12.columns
|
||||
%header
|
||||
%h2 Let's Get Started
|
||||
%h5{ bo: { if: "enterprise.type != 'own'" } } Woot! First we need to know a little bit about your enterprise:
|
||||
%h5{ bo: { if: "enterprise.type == 'own'" } } Woot! First we need to know a little bit about your farm:
|
||||
|
||||
.row#enterprise-types{ 'data-equalizer' => true, bo: { if: "enterprise.type != 'single'" } }
|
||||
.small-12.columns.field
|
||||
%form{ name: 'details', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('contact',details)" } }
|
||||
|
||||
.row
|
||||
.small-12.medium-9.large-12.columns.end
|
||||
.field
|
||||
%label{ for: 'enterprise_name', bo: { if: "enterprise.type != 'own'" } } Enterprise Name:
|
||||
%label{ for: 'enterprise_name', bo: { if: "enterprise.type == 'own'" } } Farm Name:
|
||||
%input.chunky{ id: 'enterprise_name', name: 'name', placeholder: "e.g. Charlie's Awesome Farm", required: true, ng: { model: 'enterprise.name' } }
|
||||
%span.error{ ng: { show: "details.name.$error.required && submitted" } }
|
||||
Please choose a unique name for your enterprise
|
||||
|
||||
.row
|
||||
.small-12.medium-9.large-6.columns
|
||||
.field
|
||||
%label{ for: 'enterprise_address' } Address line 1:
|
||||
%input.chunky{ id: 'enterprise_address', name: 'address1', required: true, placeholder: "e.g. 123 Cranberry Drive", required: true, ng: { model: 'enterprise.address.address1' } }
|
||||
%span.error{ ng: { show: "details.address1.$error.required && submitted" } }
|
||||
Please enter an address
|
||||
.field
|
||||
%label{ for: 'enterprise_address2' } Address line 2:
|
||||
%input.chunky{ id: 'enterprise_address2', name: 'address2', required: false, placeholder: "", required: false, ng: { model: 'enterprise.address.address2' } }
|
||||
|
||||
.small-12.medium-9.large-6.columns.end
|
||||
.row
|
||||
.small-12.columns
|
||||
%label Choose one:
|
||||
.small-12.medium-8.large-8.columns
|
||||
.field
|
||||
%label{ for: 'enterprise_city' } Suburb:
|
||||
%input.chunky{ id: 'enterprise_city', name: 'city', required: true, placeholder: "e.g. Northcote", ng: { model: 'enterprise.address.city' } }
|
||||
%span.error{ ng: { show: "details.city.$error.required && submitted" } }
|
||||
Please enter a suburb
|
||||
.small-12.medium-4.large-4.columns
|
||||
.field
|
||||
%label{ for: 'enterprise_zipcode' } Postcode:
|
||||
%input.chunky{ id: 'enterprise_zipcode', name: 'zipcode', required: true, placeholder: "e.g. 3070", ng: { model: 'enterprise.address.zipcode' } }
|
||||
%span.error{ ng: { show: "details.zipcode.$error.required && submitted" } }
|
||||
Postcode required
|
||||
.row
|
||||
.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)}" } }
|
||||
.left
|
||||
/ %render-svg{ path: "/assets/map-icon-producer.svg" }
|
||||
%h4 I'm A Producer
|
||||
%p Producers make yummy things to eat &/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
|
||||
.small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
|
||||
%a.panel#hub-panel{ href: "#", ng: { click: "enterprise.is_distributor = true; enterprise.is_primary_producer = false", class: "{selected: (enterprise.is_distributor && !enterprise.is_primary_producer)}" } }
|
||||
.left
|
||||
/ %render-svg{ path: "/assets/map-icon-hub.svg" }
|
||||
%h4 I'm A Hub
|
||||
%p Hubs connect the producer to the eater. Hubs can be co-ops, independent retailers, buying groups, wholesalers, CSA box schemes, farm-gate stalls, etc.
|
||||
.small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
|
||||
%a.panel#both-panel{ href: "#", ng: { click: "enterprise.is_distributor = true; enterprise.is_primary_producer = true", class: "{selected: (enterprise.is_distributor && enterprise.is_primary_producer)}" } }
|
||||
.left
|
||||
/ %render-svg{path: "/assets/map-icon-both.svg"}
|
||||
%h4 I'm Both
|
||||
%p Hey there, Jack-of-all-trades! Not only do you produce things to eat &/or drink, you also want to sell your yummies through an Open Food Network shopfront.
|
||||
.small-12.medium-4.large-4.columns
|
||||
.field
|
||||
%label{ for: 'enterprise_state' } State:
|
||||
%select.chunky{ id: 'enterprise_state', name: 'state', ng: { model: 'enterprise.address.state_id', options: 's.id as s.abbr for s in enterprise.country.states', show: 'countryHasStates()', required: 'countryHasStates()' } }
|
||||
%span.error{ ng: { show: "details.state.$error.required && submitted" } }
|
||||
State required
|
||||
.small-12.medium-8.large-8.columns
|
||||
.field
|
||||
%label{ for: 'enterprise_country' } Country:
|
||||
%select.chunky{ id: 'enterprise_country', name: 'country', required: true, ng: { model: 'enterprise.country', options: 'c as c.name for c in countries' } }
|
||||
%span.error{ ng: { show: "details.country.$error.required && submitted" } }
|
||||
Please select a country
|
||||
/ .small-12.medium-12.large-5.hide-for-small-only
|
||||
/ %h6
|
||||
/ Location display
|
||||
/ %i.ofn-i_013-help.has-tip{ 'data-tooltip' => true, title: "Choose how you want to display your enterprise's address on the Open Food Network. By default, full location is shown everywhere including street name and number."}
|
||||
/ .row
|
||||
/ .small-12.columns
|
||||
/ %label.indent-checkbox
|
||||
/ %input{ type: 'checkbox', id: 'enterpise_suburb_only', ng: { model: 'enterprise.suburb_only' } }
|
||||
/ Hide my street name and street number from the public (ie. only show the suburb)
|
||||
/ .small-12.columns
|
||||
/ %label.indent-checkbox
|
||||
/ %input{ type: 'checkbox', id: 'enterprise_on_map', ng: { model: 'enterprise.on_map' } }
|
||||
/ Blur my location on the map (show an approximate, not exact pin)
|
||||
|
||||
|
||||
.row.buttons
|
||||
.small-12.columns
|
||||
%hr
|
||||
%input.button.primary.right{ type: "submit", value: "Continue" }
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
.container#registration-finished
|
||||
.header
|
||||
%h2 Well done!
|
||||
%h5
|
||||
You have successfully completed the profile for
|
||||
%span.brick{"ng-show" => "enterprise.is_distributor"}
|
||||
{{ enterprise.name }}
|
||||
%span.turquoise{"ng-show" => "!enterprise.is_distributor" }
|
||||
{{ enterprise.name }}
|
||||
.content{ style: 'text-align: center'}
|
||||
%h3 Why not check it out on the Open Food Network?
|
||||
%a.button.primary{ type: "button", href: "/map" } Go to Map Page >
|
||||
.row
|
||||
.small-12.columns.pad-top
|
||||
%header
|
||||
%h2 Finished!
|
||||
.panel.callout
|
||||
%p
|
||||
Thanks for filling out the details for
|
||||
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
|
||||
{{ enterprise.name }}
|
||||
%p You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin.
|
||||
.row
|
||||
.small-12.columns.text-center
|
||||
%h4
|
||||
Activate
|
||||
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
|
||||
{{ enterprise.name }}
|
||||
|
||||
%br
|
||||
%br
|
||||
%p
|
||||
We've sent a confirmation email to
|
||||
%strong {{ enterprise.email }}.
|
||||
%br Please follow the instructions there to make your enterprise visible on the Open Food Network.
|
||||
|
||||
%h3 Next step - add some products:
|
||||
%a.button.primary{ type: "button", href: "/admin/products/new" } Add a Product >
|
||||
%a.button.primary{ type: "button", href: "/" } Open Food Network home >
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
.container#registration-images{ 'nv-file-drop' => true, uploader: "imageUploader", options:"{ alias: imageStep }", ng: { controller: "EnterpriseImageCtrl" } }
|
||||
.header
|
||||
%h2 Thanks!
|
||||
%h5 Let's upload some pretty pictures so your profile looks great! :)
|
||||
%ng-include{ src: "'registration/steps.html'" }
|
||||
.row
|
||||
.small-12.columns
|
||||
%header
|
||||
%h2 Thanks!
|
||||
%h5 Let's upload some pretty pictures so your profile looks great! :)
|
||||
|
||||
%form{ name: 'images', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "select('social')" } }
|
||||
.row{ ng: { repeat: 'image_step in imageSteps', show: "imageStep == image_step" } }
|
||||
%ng-include{ src: "'registration/images/'+ image_step + '.html'" }
|
||||
|
||||
.row.buttons.pad-top{ ng: { if: "imageStep == 'logo'" } }
|
||||
.small-12.columns
|
||||
%input.button.primary{ type: "button", value: "Back", ng: { click: "select('about')" } }
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('about')" } }
|
||||
|
||||
%input.button.primary{ type: "button", value: "Continue", ng: { click: "imageSelect('promo')" } }
|
||||
%input.button.primary.right{ type: "button", value: "Continue", ng: { click: "imageSelect('promo')" } }
|
||||
|
||||
.row.buttons.pad-top{ ng: { if: "imageStep == 'promo'" } }
|
||||
.small-12.columns
|
||||
%input.button.primary{ type: "button", value: "Back", ng: { click: "imageSelect('logo')" } }
|
||||
|
||||
%input.button.primary{ type: "submit", value: "Continue" }
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "imageSelect('logo')" } }
|
||||
%input.button.primary.right{ type: "submit", value: "Continue" }
|
||||
|
||||
@@ -36,6 +36,10 @@
|
||||
.row.pad-top
|
||||
.small-12.columns.center
|
||||
#image-placeholder.logo
|
||||
%img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
|
||||
.message{ ng: { hide: "imageSrc()" } }
|
||||
%img{ ng: { show: "imageSrc() && !imageUploader.isUploading", src: '{{ imageSrc() }}' } }
|
||||
.message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
|
||||
Your logo will appear here for review once uploaded
|
||||
.loading{ ng: { hide: "!imageUploader.isUploading" } }
|
||||
%img.spinner{ src: "/assets/loading.gif" }
|
||||
%br/
|
||||
Uploading...
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
.row.pad-top
|
||||
.small-12.columns.center
|
||||
#image-placeholder.promo
|
||||
%img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
|
||||
.message{ ng: { hide: "imageSrc()" } }
|
||||
%img{ ng: { show: "imageSrc() && !imageUploader.isUploading", src: '{{ imageSrc() }}' } }
|
||||
.message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
|
||||
Your logo will appear here for review once uploaded
|
||||
.loading{ ng: { hide: "!imageUploader.isUploading" } }
|
||||
%img.spinner{ src: "/assets/loading.gif" }
|
||||
%br/
|
||||
Uploading...
|
||||
|
||||
@@ -1,39 +1,45 @@
|
||||
%div
|
||||
.header
|
||||
%h2 Hi there!
|
||||
%h4 This wizard will step you through creating a profile
|
||||
.row
|
||||
.small-12.medium-3.large-2.columns.text-right.hide-for-small-only
|
||||
%img{:src => "/assets/potatoes.png"}
|
||||
.small-12.medium-9.large-10.columns
|
||||
%p
|
||||
Your profile gives you an online presence on the
|
||||
%strong Open Food Network,
|
||||
allowing you to easily connect with potential customers or partners. You can always choose to update your info later, as well as choose to upgrade your Profile to and Online Store, where you can sell products, track orders and receive payments. Creating a profile takes about 5-10 minutes.
|
||||
.row{ 'data-equalizer' => true }
|
||||
.small-12.medium-6.large-6.columns.pad-top{ 'data-equalizer-watch' => true }
|
||||
%h5 You'll need the following:
|
||||
%ul.check-list
|
||||
%li
|
||||
Your enterprise address and contact details
|
||||
%li
|
||||
Your logo image
|
||||
%li
|
||||
A pretty picture for your profile header
|
||||
%li
|
||||
Some 'About Us' text
|
||||
|
||||
.small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true}
|
||||
.highlight-box
|
||||
%h5 Your profile entitles you to:
|
||||
%ul.small-block-grid-1
|
||||
%li
|
||||
%i.ofn-i_020-search
|
||||
A searchable listing
|
||||
%li
|
||||
%i.ofn-i_040-hub
|
||||
A pin on the OFN map
|
||||
.row
|
||||
.small-12.columns
|
||||
.row
|
||||
.small-12.columns
|
||||
%header
|
||||
%h2 Hi there!
|
||||
%h4
|
||||
%small
|
||||
%i.ofn-i_040-hub
|
||||
Create your enterprise profile
|
||||
.hide-for-large-up
|
||||
%hr
|
||||
%input.button.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
|
||||
%input.button.small.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
|
||||
%hr
|
||||
|
||||
.row{ 'data-equalizer' => true }
|
||||
.small-12.medium-12.large-6.columns.pad-top{ 'data-equalizer-watch' => true }
|
||||
%h5 You'll need:
|
||||
%ul.check-list
|
||||
%li
|
||||
5-10 minutes
|
||||
%li
|
||||
Enterprise address
|
||||
%li
|
||||
Primary contact details
|
||||
%li
|
||||
Your logo image
|
||||
%li
|
||||
Landscape image for your profile
|
||||
%li
|
||||
'About Us' text
|
||||
|
||||
.small-9.medium-8.large-5.columns.pad-top.end{ 'data-equalizer-watch' => true}
|
||||
%h5
|
||||
What do I get?
|
||||
%p
|
||||
Your profile helps people
|
||||
%strong find
|
||||
and
|
||||
%strong contact
|
||||
you on the Open Food Network.
|
||||
%p Use this space to tell the story of your enterprise, to help drive connections to your social and online presence.
|
||||
|
||||
.row.show-for-large-up
|
||||
.small-12.columns
|
||||
%hr
|
||||
%input.button.primary.right{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
%div
|
||||
.header.center
|
||||
%h2 Oh no!
|
||||
%h4 You have reached the limit!
|
||||
.row
|
||||
.small-12.medium-3.large-2.columns.text-right.hide-for-small-only
|
||||
%img{:src => "/assets/potatoes.png"}
|
||||
.small-12.medium-9.large-10.columns
|
||||
%p
|
||||
You have reached the limit for the number of enterprises you are allowed to own on the
|
||||
%strong Open Food Network.
|
||||
.row
|
||||
.small-12.columns
|
||||
%hr
|
||||
%input.button.primary{ type: "button", value: "Return to the homepage", ng: { click: "close()" } }
|
||||
.row
|
||||
.small-12.columns
|
||||
%header
|
||||
%h2 Oh no!
|
||||
%h4 You have reached the limit!
|
||||
.row
|
||||
.small-12.medium-3.large-2.columns.text-right.hide-for-small-only
|
||||
%img{:src => "/assets/potatoes.png"}
|
||||
.small-12.medium-9.large-10.columns
|
||||
%p
|
||||
You have reached the limit for the number of enterprises you are allowed to own on the
|
||||
%strong Open Food Network.
|
||||
.row
|
||||
.small-12.columns
|
||||
%hr
|
||||
%input.button.primary{ type: "button", value: "Return to the homepage", ng: { click: "close()" } }
|
||||
|
||||
@@ -1,35 +1,49 @@
|
||||
.container#registration-social
|
||||
.header
|
||||
%h2 Last step!
|
||||
%h5 How can people find {{ enterprise.name }} online?
|
||||
%ng-include{ src: "'registration/steps.html'" }
|
||||
|
||||
.row
|
||||
.small-12.columns
|
||||
%header
|
||||
%h2 Final step!
|
||||
%h5
|
||||
How can people find
|
||||
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
|
||||
{{ enterprise.name }}
|
||||
online?
|
||||
|
||||
%form{ name: 'social', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('finished',social)" } }
|
||||
.row.content
|
||||
.small-12.large-7.columns
|
||||
.row
|
||||
.small-12.columns
|
||||
%label{ for: 'enterprise_website' } Website:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_website', placeholder: "eg. openfoodnetwork.org.au", ng: { model: 'enterprise.website' } }
|
||||
.field
|
||||
%label{ for: 'enterprise_website' } Website:
|
||||
%input.chunky{ id: 'enterprise_website', placeholder: "eg. openfoodnetwork.org.au", ng: { model: 'enterprise.website' } }
|
||||
.row
|
||||
.small-12.columns
|
||||
%label{ for: 'enterprise_facebook' } Facebook:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_facebook', placeholder: "eg. www.facebook.com/PageNameHere", ng: { model: 'enterprise.facebook' } }
|
||||
.field
|
||||
%label{ for: 'enterprise_facebook' } Facebook:
|
||||
%input.chunky{ id: 'enterprise_facebook', placeholder: "eg. www.facebook.com/PageNameHere", ng: { model: 'enterprise.facebook' } }
|
||||
.row
|
||||
.small-12.columns
|
||||
%label{ for: 'enterprise_linkedin' } LinkedIn:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_linkedin', placeholder: "eg. www.linkedin.com/YourNameHere", ng: { model: 'enterprise.linkedin' } }
|
||||
.field
|
||||
%label{ for: 'enterprise_linkedin' } LinkedIn:
|
||||
%input.chunky{ id: 'enterprise_linkedin', placeholder: "eg. www.linkedin.com/YourNameHere", ng: { model: 'enterprise.linkedin' } }
|
||||
.small-12.large-5.columns
|
||||
.row
|
||||
.small-12.columns
|
||||
%label{ for: 'enterprise_twitter' } Twitter:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_twitter', placeholder: "eg. @twitter_handle", ng: { model: 'enterprise.twitter' } }
|
||||
.field
|
||||
%label{ for: 'enterprise_twitter' } Twitter:
|
||||
%input.chunky{ id: 'enterprise_twitter', placeholder: "eg. @twitter_handle", ng: { model: 'enterprise.twitter' } }
|
||||
.row
|
||||
.small-12.columns
|
||||
%label{ for: 'enterprise_instagram' } Instagram:
|
||||
%input.chunky.small-12.columns{ id: 'enterprise_instagram', placeholder: "eg. @instagram_handle", ng: { model: 'enterprise.instagram' } }
|
||||
.field
|
||||
%label{ for: 'enterprise_instagram' } Instagram:
|
||||
%input.chunky{ id: 'enterprise_instagram', placeholder: "eg. @instagram_handle", ng: { model: 'enterprise.instagram' } }
|
||||
|
||||
.row.buttons
|
||||
.small-12.columns
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('images')" } }
|
||||
|
||||
%input.button.primary{ type: "submit", value: "Continue" }
|
||||
%input.button.primary.right{ type: "submit", value: "Continue" }
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
.row#progress-bar
|
||||
.small-12.medium-2.columns.item{ ng: { repeat: 'step in steps', class: "{active: (currentStep() == step),'show-for-medium-up': (currentStep() != step)}" } }
|
||||
{{ $index+1 + ". " + step }}
|
||||
|
||||
|
||||
46
app/assets/javascripts/templates/registration/type.html.haml
Normal file
46
app/assets/javascripts/templates/registration/type.html.haml
Normal file
@@ -0,0 +1,46 @@
|
||||
.container#registration-type{bindonce: true}
|
||||
|
||||
%ng-include{ src: "'registration/steps.html'" }
|
||||
|
||||
.row
|
||||
.small-12.columns
|
||||
%header
|
||||
%h2
|
||||
Last step to add
|
||||
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
|
||||
{{ enterprise.name }}!
|
||||
%h4
|
||||
Are you a producer?
|
||||
|
||||
%form{ name: 'type', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "create(type)" } }
|
||||
.row#enterprise-types{ 'data-equalizer' => true, bo: { if: "enterprise.type != 'own'" } }
|
||||
.small-12.columns.field
|
||||
.row
|
||||
.small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true }
|
||||
%a.btnpanel#producer-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = true", class: "{selected: enterprise.is_primary_producer}" } }
|
||||
%i.ofn-i_059-producer
|
||||
%h4 Yes, I'm a producer
|
||||
|
||||
.small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true }
|
||||
%a.btnpanel#hub-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = false", class: "{selected: enterprise.is_primary_producer == false}" } }
|
||||
%i.ofn-i_063-hub
|
||||
%h4 No, I'm not a producer
|
||||
|
||||
.row
|
||||
.small-12.columns
|
||||
%input.chunky{ id: 'enterprise_is_primary_producer', name: 'is_primary_producer', hidden: true, required: true, ng: { model: 'enterprise.is_primary_producer' } }
|
||||
%span.error{ ng: { show: "type.is_primary_producer.$error.required && submitted" } }
|
||||
Please choose one. Are you are producer?
|
||||
.row
|
||||
.small-12.columns
|
||||
.panel.callout
|
||||
.left
|
||||
%i.ofn-i_013-help
|
||||
|
||||
%p Producers make yummy things to eat &/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
|
||||
/ %p Hubs connect the producer to the eater. Hubs can be co-ops, independent retailers, buying groups, wholesalers, CSA box schemes, farm-gate stalls, etc.
|
||||
|
||||
.row.buttons
|
||||
.small-12.columns
|
||||
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('contact')" } }
|
||||
%input.button.primary.right{ type: "submit", value: "Continue" }
|
||||
15
app/assets/stylesheets/admin/alert.css.sass
Normal file
15
app/assets/stylesheets/admin/alert.css.sass
Normal file
@@ -0,0 +1,15 @@
|
||||
.alert
|
||||
border: 3px solid #919191
|
||||
border-radius: 6px
|
||||
margin-bottom: 20px
|
||||
color: #919191
|
||||
padding: 5px 10px
|
||||
h6
|
||||
color: #919191
|
||||
.message
|
||||
font-weight: bold
|
||||
&:hover
|
||||
border-color: #DA5354
|
||||
color: #DA5354
|
||||
h6
|
||||
color: #DA5354
|
||||
@@ -9,6 +9,7 @@
|
||||
*= require admin/spree_promo
|
||||
|
||||
*= require shared/jquery-ui-timepicker-addon
|
||||
*= require shared/textAngular.min
|
||||
|
||||
*= require_self
|
||||
*= require_tree .
|
||||
|
||||
72
app/assets/stylesheets/admin/change_type_form.css.sass
Normal file
72
app/assets/stylesheets/admin/change_type_form.css.sass
Normal file
@@ -0,0 +1,72 @@
|
||||
@import ../darkswarm/branding
|
||||
@import ../darkswarm/mixins
|
||||
|
||||
#change_type
|
||||
section
|
||||
margin: 2em 0 0 0
|
||||
&, & *
|
||||
color: #5498da
|
||||
|
||||
.description
|
||||
background-color: #eff5fc
|
||||
margin-top: -2em
|
||||
padding: 4em 2em 2em 1em
|
||||
@media all and (max-width: 786px)
|
||||
margin-bottom: 2em
|
||||
|
||||
.admin-cta
|
||||
border: 1px solid #5498da
|
||||
@include border-radius(3px)
|
||||
text-align: center
|
||||
padding: 1em
|
||||
|
||||
.error
|
||||
display: block
|
||||
color: #f57e80
|
||||
border: 1px solid #f57e80
|
||||
background-color: #fde6e7
|
||||
@include border-radius(3px)
|
||||
margin-bottom: 1em
|
||||
padding: 0.5em
|
||||
|
||||
a.selector
|
||||
position: relative
|
||||
border: 2px solid black
|
||||
text-align: center
|
||||
width: 100%
|
||||
cursor: pointer
|
||||
&, & *
|
||||
color: white
|
||||
&:after, &:before
|
||||
top: 100%
|
||||
left: 50%
|
||||
border: solid transparent
|
||||
content: " "
|
||||
height: 0
|
||||
width: 0
|
||||
position: absolute
|
||||
pointer-events: none
|
||||
&:after
|
||||
border-color: rgba(136, 183, 213, 0)
|
||||
border-top-color: #5498da
|
||||
border-width: 12px
|
||||
margin-left: -12px
|
||||
&:hover
|
||||
&:after
|
||||
border-top-color: #9fc820
|
||||
&:before
|
||||
border-color: rgba(84, 152, 218, 0)
|
||||
border-top-color: black
|
||||
border-width: 15px
|
||||
margin-left: -15px
|
||||
.bottom
|
||||
background: repeating-linear-gradient(60deg, rgba(84, 152, 218, 0), rgba(84, 152, 218, 0) 5px, rgba(255, 255, 255, 0.25) 5px, rgba(255, 255, 255, 0.25) 10px)
|
||||
margin-top: 1em
|
||||
margin-left: -15px
|
||||
margin-right: -15px
|
||||
padding: 5px
|
||||
text-transform: uppercase
|
||||
&.selected
|
||||
background-color: black
|
||||
&:after, &:hover &:after
|
||||
border-top-color: black
|
||||
@@ -0,0 +1,8 @@
|
||||
#trial_progress_bar
|
||||
position: fixed
|
||||
bottom: 0px
|
||||
width: 100%
|
||||
padding: 8px 10px
|
||||
font-weight: bold
|
||||
background-color: #5498da
|
||||
color: white
|
||||
31
app/assets/stylesheets/admin/dashboard-single-ent.css.sass
Normal file
31
app/assets/stylesheets/admin/dashboard-single-ent.css.sass
Normal file
@@ -0,0 +1,31 @@
|
||||
@import ../darkswarm/branding
|
||||
@import ../darkswarm/mixins
|
||||
|
||||
|
||||
.alert-box
|
||||
display: block
|
||||
background-color: #eff5dc
|
||||
border: 1px solid #9fc820
|
||||
color: #666
|
||||
margin-top: 1em
|
||||
margin-bottom: 1em
|
||||
@include border-radius(3px)
|
||||
transition: opacity 300ms ease-out
|
||||
padding: 0.77778em 1.33333em 0.77778em 0.77778em
|
||||
a.close
|
||||
float: right
|
||||
|
||||
|
||||
.dashboard_item.single-ent
|
||||
.header
|
||||
padding: 0.77778em 1.33333em 0.77778em 0.77778em
|
||||
height: auto !important
|
||||
.list
|
||||
.button.bottom
|
||||
width: 100%
|
||||
|
||||
.button.big
|
||||
width: 100%
|
||||
font-size: 1rem
|
||||
@include border-radius(25px)
|
||||
padding: 15px
|
||||
@@ -156,4 +156,4 @@ div.dashboard_item
|
||||
background-color: #9fc820
|
||||
&.bottom
|
||||
border-radius: 0px 0px 6px 6px
|
||||
padding: 15px 15px
|
||||
padding: 15px 15px
|
||||
|
||||
@@ -210,3 +210,24 @@ table#listing_enterprise_groups {
|
||||
color: #575757;
|
||||
}
|
||||
|
||||
.field_with_errors > input {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
// textAngular wysiwyg
|
||||
text-angular {
|
||||
.ta-scroll-window > .ta-bind {
|
||||
max-height: 400px;
|
||||
min-height: 100px;
|
||||
}
|
||||
.ta-scroll-window.form-control {
|
||||
min-height: 100px;
|
||||
}
|
||||
.btn-group {
|
||||
display: inline;
|
||||
margin-right: 8px;
|
||||
button {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ div.sidebar_item
|
||||
color: #DA5354
|
||||
|
||||
.list-item
|
||||
.icon-arrow-right
|
||||
padding-top: 6px
|
||||
font-size: 20px
|
||||
border: solid #5498da
|
||||
border-width: 0px 1px 0px 1px
|
||||
a.alpha, span.alpha
|
||||
@@ -40,7 +43,6 @@ div.sidebar_item
|
||||
margin-left: -1px
|
||||
padding: 10px 2px 10px 5%
|
||||
overflow: hidden
|
||||
max-width: 160px
|
||||
text-overflow: ellipsis
|
||||
span.omega
|
||||
padding: 8px 18px 8px 0px
|
||||
@@ -72,4 +74,4 @@ div.sidebar_item
|
||||
background-color: #DA5354
|
||||
&:hover
|
||||
background-color: #9fc820
|
||||
|
||||
|
||||
|
||||
17
app/assets/stylesheets/admin/welcome.css.sass
Normal file
17
app/assets/stylesheets/admin/welcome.css.sass
Normal file
@@ -0,0 +1,17 @@
|
||||
@import ../darkswarm/branding
|
||||
@import ../darkswarm/mixins
|
||||
|
||||
#welcome_page
|
||||
header
|
||||
text-align: center
|
||||
padding: 4em 2em
|
||||
@include fullbg
|
||||
background-image: url('/assets/home/tagline-bg.jpg')
|
||||
background-repeat: no-repeat
|
||||
background-position: center center
|
||||
margin-bottom: 2em
|
||||
p
|
||||
text-transform: uppercase
|
||||
font-weight: 300
|
||||
&, & *
|
||||
color: white
|
||||
@@ -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
|
||||
|
||||
@@ -2,44 +2,25 @@
|
||||
@import mixins
|
||||
|
||||
#registration-modal
|
||||
.header
|
||||
header
|
||||
text-align: center
|
||||
background-color: #efefef
|
||||
padding-bottom: 1rem
|
||||
// background-color: #efefef
|
||||
@media all and (max-width: 64em)
|
||||
text-align: left
|
||||
.container
|
||||
background-color: #ffffff
|
||||
.content
|
||||
// margin-bottom: 15px
|
||||
|
||||
i
|
||||
font-size: 150%
|
||||
|
||||
.buttons
|
||||
|
||||
ofn-inline-flash
|
||||
display: block
|
||||
padding: 15px
|
||||
position: relative
|
||||
margin-bottom: 10px
|
||||
&.brick
|
||||
background-color: $clr-brick-light
|
||||
border: 2px solid $clr-brick
|
||||
color: $clr-brick
|
||||
&.turquoise
|
||||
background-color: $clr-turquoise-light
|
||||
border: 2px solid $clr-turquoise
|
||||
color: $clr-turquoise
|
||||
.close-button
|
||||
position: absolute
|
||||
top: 0px
|
||||
right: 0px
|
||||
|
||||
.field
|
||||
margin-bottom: 15px
|
||||
margin-bottom: 1em
|
||||
|
||||
input.chunky
|
||||
.chunky
|
||||
padding: 8px
|
||||
font-size: 105%
|
||||
font-size: 1rem
|
||||
margin: 0
|
||||
width: 100%
|
||||
|
||||
label.indent-checkbox
|
||||
display: block
|
||||
@@ -51,9 +32,9 @@
|
||||
label
|
||||
margin-bottom: 3px
|
||||
|
||||
ol, ul
|
||||
// font-size: 80%
|
||||
ol, ul, p
|
||||
font-size: 0.875rem
|
||||
ol, ul
|
||||
padding: 0
|
||||
margin: 0
|
||||
ol
|
||||
@@ -62,22 +43,24 @@
|
||||
.highlight-box
|
||||
background: white
|
||||
padding: 1rem 1.2rem
|
||||
@media all and (max-width: 640px)
|
||||
@media all and (max-width: 64em)
|
||||
margin-top: 1rem
|
||||
|
||||
#progress-bar
|
||||
margin-bottom: 15px
|
||||
.item
|
||||
padding: 12px 0px
|
||||
font-size: 0.75rem
|
||||
padding: 10px 0px
|
||||
text-transform: uppercase
|
||||
text-align: center
|
||||
background-color: #333
|
||||
border: 2px solid #333
|
||||
background-color: $clr-blue
|
||||
border: 2px solid $clr-blue
|
||||
color: #fff
|
||||
.item.active
|
||||
background-color: #cccccc
|
||||
border: 2px solid #333
|
||||
color: #333
|
||||
background-color: $disabled-light
|
||||
border: 2px solid $clr-blue
|
||||
color: $clr-blue
|
||||
font-weight: 700
|
||||
@include box-shadow(inset 0 0 1px 0 #fff)
|
||||
|
||||
|
||||
@@ -110,39 +93,57 @@
|
||||
font-size: 18px
|
||||
font-weight: bold
|
||||
color: #373737
|
||||
background-color: #e1e1e1
|
||||
background-color: #f1f1f1
|
||||
text-align: center
|
||||
border: 3px dashed #494949
|
||||
margin-left: auto
|
||||
margin-right: auto
|
||||
.spinner
|
||||
width: 100px
|
||||
&.logo
|
||||
.message
|
||||
padding-top: 6em
|
||||
.loading
|
||||
padding-top: 4em
|
||||
width: 306px
|
||||
height: 306px
|
||||
&.promo
|
||||
.message
|
||||
padding-top: 4em
|
||||
.loading
|
||||
padding-top: 1em
|
||||
width: 726px
|
||||
height: 166px
|
||||
|
||||
|
||||
#registration-details
|
||||
#registration-type
|
||||
#enterprise-types
|
||||
a.panel
|
||||
a.btnpanel
|
||||
display: block
|
||||
padding: 1rem
|
||||
margin-bottom: 1rem
|
||||
background-color: #efefef
|
||||
color: black
|
||||
@media all and (min-width: 768px)
|
||||
min-height: 200px
|
||||
text-align: center
|
||||
border: 1px solid transparent
|
||||
i
|
||||
font-size: 3rem
|
||||
h4
|
||||
margin-top: 1rem
|
||||
|
||||
&:hover
|
||||
background-color: #fff
|
||||
|
||||
&#producer-panel:hover
|
||||
border: 1px solid $clr-turquoise
|
||||
&, & *
|
||||
color: $clr-turquoise
|
||||
|
||||
&#hub-panel:hover, &#both-panel:hover
|
||||
border: 1px solid $clr-brick
|
||||
&, & *
|
||||
color: $clr-brick
|
||||
|
||||
&.selected
|
||||
&, & *
|
||||
color: #fff
|
||||
|
||||
@@ -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
app/assets/stylesheets/shared/textAngular.min.css
vendored
Normal file
1
app/assets/stylesheets/shared/textAngular.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.ta-scroll-window.form-control{height:auto;min-height:300px;overflow:auto;font-family:inherit;font-size:100%;position:relative;padding:0}.ta-root.focussed .ta-scroll-window.form-control{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.ta-editor.ta-html{min-height:300px;height:auto;overflow:auto;font-family:inherit;font-size:100%}.ta-scroll-window>.ta-bind{height:auto;min-height:300px;padding:6px 12px}.ta-root .ta-resizer-handle-overlay{z-index:100;position:absolute;display:none}.ta-root .ta-resizer-handle-overlay>.ta-resizer-handle-info{position:absolute;bottom:16px;right:16px;border:1px solid #000;background-color:#FFF;padding:0 4px;opacity:.7}.ta-root .ta-resizer-handle-overlay>.ta-resizer-handle-background{position:absolute;bottom:5px;right:5px;left:5px;top:5px;border:1px solid #000;background-color:rgba(0,0,0,.2)}.ta-root .ta-resizer-handle-overlay>.ta-resizer-handle-corner{width:10px;height:10px;position:absolute}.ta-root .ta-resizer-handle-overlay>.ta-resizer-handle-corner-tl{top:0;left:0;border-left:1px solid #000;border-top:1px solid #000}.ta-root .ta-resizer-handle-overlay>.ta-resizer-handle-corner-tr{top:0;right:0;border-right:1px solid #000;border-top:1px solid #000}.ta-root .ta-resizer-handle-overlay>.ta-resizer-handle-corner-bl{bottom:0;left:0;border-left:1px solid #000;border-bottom:1px solid #000}.ta-root .ta-resizer-handle-overlay>.ta-resizer-handle-corner-br{bottom:0;right:0;border:1px solid #000;cursor:se-resize;background-color:#fff}
|
||||
@@ -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;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user