Compare commits

...

289 Commits
0.6.3 ... 0.7.0

Author SHA1 Message Date
Rob Harrington
43d3955627 Change wording of trial option on change_type_form 2014-10-25 19:56:52 +11:00
Rob Harrington
6155600cb2 Set environment for payment methods unless admin 2014-10-24 18:15:48 +11:00
Rob Harrington
8385bff55e Make admins get multi enterprise dashboard 2014-10-24 17:59:58 +11:00
summerscope
928e5dc474 Make styling more specific to single enterprise dashboard user only 2014-10-24 16:39:59 +11:00
Rob Harrington
cc0e205f50 Merge master into onbaording 2014-10-24 15:36:59 +11:00
Rob Harrington
80b36992f9 Merge in remote branch 2014-10-24 15:28:40 +11:00
Rob Harrington
a157528974 Adding specs for single ent dash and remove product ability for profiles 2014-10-24 15:27:08 +11:00
Rob Harrington
8b819539e7 Fixing specs 2014-10-24 14:52:59 +11:00
summerscope
2eb152f63e Change class name for big button; change labels for submit buttons 2014-10-24 14:49:09 +11:00
summerscope
c733ca251e Styling for big button 2014-10-24 14:48:46 +11:00
summerscope
d388747a81 Make margine appear for small devices only 2014-10-24 14:48:29 +11:00
Rob Harrington
8ac367675f Adding big button class to CTA 2014-10-24 14:24:55 +11:00
Rob Harrington
96516a8ff3 User can switch between trialling a shopfront and not trialling a shopfront 2014-10-24 14:12:47 +11:00
Rob Harrington
3e002c6f82 Fiddle with text 2014-10-24 13:34:49 +11:00
Rob Harrington
20e2cb4ecc Set visibility to false for enterprises created through registration process 2014-10-24 13:31:20 +11:00
Rob Harrington
b0d8290dab Add alert for visibility to single ent dash 2014-10-24 13:28:25 +11:00
Rob Harrington
8603cf685e Merge remote-tracking branch 'origin/onboarding' into onboarding 2014-10-24 13:03:04 +11:00
Rob Harrington
b182c6afc8 Merge in remote changes 2014-10-24 13:02:26 +11:00
summerscope
0d73d8f043 Fix layout add required class 2014-10-24 13:01:56 +11:00
Rob Harrington
498b51cedb Switching out chevron on Change Type button 2014-10-24 12:54:21 +11:00
summerscope
01cb39a93f Error messages specific to use case 2014-10-24 12:54:06 +11:00
summerscope
b172c4fd4f Search query make empty string rather than undefined 2014-10-24 12:53:04 +11:00
summerscope
b3ac06e46c Fix icon type to match nav bar 2014-10-24 12:42:14 +11:00
summerscope
68cb3efc50 Markup fixes for single enterprise dashboard (first state) 2014-10-24 12:39:25 +11:00
summerscope
e32ab7b4b7 Single enterprise dashboard styling 2014-10-24 12:39:08 +11:00
Rob Harrington
d0c3502f27 Adding trial progress bar 2014-10-24 12:32:05 +11:00
summerscope
631386ced4 Tweaking markup 2014-10-24 11:48:53 +11:00
summerscope
982be3a563 Stylesheet for single enterprise user dashboard components 2014-10-24 11:48:39 +11:00
summerscope
76c6c260d1 Add row containers to make grid nesting work 2014-10-24 11:48:13 +11:00
summerscope
0b3e293b38 Remove whitespace, add alert box 2014-10-24 11:26:58 +11:00
Rob Harrington
f40b4d9d03 Different text for CTA button depending on context 2014-10-24 11:22:57 +11:00
Rob Harrington
900ef4ddcc Change type form is aware of existing state of enterprise 2014-10-24 11:12:54 +11:00
Rob Harrington
911d1e3dc4 Add down chevron to change type button on single ent dash 2014-10-24 11:02:48 +11:00
Rob Harrington
f03c7ba02d Rename sellCtrl to changeTypeFormCtrl 2014-10-24 11:02:16 +11:00
summerscope
49a2b774b0 Tweak language in helper 2014-10-24 10:56:03 +11:00
Rob Harrington
f6b0324456 Add change type form to single enterprise dashboard 2014-10-24 10:43:04 +11:00
Rob Harrington
46ab424655 Moving welcomeCrtl to enterprise module as sellsCtrl 2014-10-24 09:10:45 +11:00
Rob Harrington
d2efd25e8d Pull out type change form into a partial 2014-10-24 08:54:08 +11:00
summerscope
3c839be743 Tweak styling for error message to be consistent with other form error styling in admin 2014-10-23 17:24:56 +11:00
summerscope
cf06cab533 Tweak header to be consistent with other admin pages 2014-10-23 17:23:58 +11:00
Rohan Mitchell
9bc8531850 Add comment 2014-10-23 16:48:16 +11:00
Rohan Mitchell
ee5cd599aa Add basic details for the single enterprise dashboard 2014-10-23 16:44:16 +11:00
Rohan Mitchell
aea8ab4c7f Move #manages_one_enterprise? from User model to Permissions 2014-10-23 16:44:16 +11:00
Rob Harrington
e1cf5ceb57 Can set producer_profile_only using welcome page 2014-10-23 16:42:00 +11:00
Rob Harrington
996b2f2604 Adding 'producer_profile_only' flag to enterprises 2014-10-23 16:42:00 +11:00
Rob Harrington
d94ca0174a Registration process sets sells to 'unspecified' 2014-10-23 16:42:00 +11:00
Rohan Mitchell
f09698be47 Select all works on simple order cycles edit interface 2014-10-23 15:54:52 +11:00
Rohan Mitchell
7faf6e12ea Clean up simple order cycle interface 2014-10-23 15:53:16 +11:00
summerscope
4f2327f05c More styling for Next button and error message 2014-10-23 15:46:56 +11:00
Rob Harrington
d50cd023d4 Adding login nav to header on bare_admin layout 2014-10-23 15:38:06 +11:00
summerscope
ce346d3bca Styling stripes with CSS3, remove the image instead 2014-10-23 15:17:33 +11:00
Rob Harrington
e67f039791 Merging in remote changes 2014-10-23 14:53:21 +11:00
Rob Harrington
e9a6c9d0ce Adding header to welcome page 2014-10-23 14:50:56 +11:00
Rob Harrington
67c82e81de Fixing form on welcome page 2014-10-23 14:41:00 +11:00
summerscope
04af954432 Tweak language 2014-10-23 14:33:19 +11:00
Rob Harrington
bcc8198019 Merge in changes on remote branch 2014-10-23 14:30:56 +11:00
summerscope
d6947b119f Welcome markup make alternative markup consistent 2014-10-23 14:28:53 +11:00
summerscope
204c7d9690 Selected state push 2014-10-23 14:26:52 +11:00
Rob Harrington
77c0e36ed6 Adding input validation to welcome page 2014-10-23 14:23:50 +11:00
summerscope
694724d177 Refactoring and styling Welcome screen dashboard admin WIP 2014-10-23 14:23:35 +11:00
summerscope
bf9cd4a12b Tweak image add gradient blur and slightly less dark 2014-10-23 14:23:23 +11:00
summerscope
f5aae7d214 Pretty stripy background tile 2014-10-23 14:23:04 +11:00
Rohan Mitchell
bf61d12bfa Merge branch 'simple-order-cycles'
Conflicts:
	app/views/admin/order_cycles/_row.html.haml
2014-10-23 12:11:34 +11:00
Rob Harrington
7d9c5f9e2c Adding form elements for submission of sells preferences on welcome page 2014-10-23 11:40:11 +11:00
Rob Harrington
b11c291df1 Add set_sells controller action for enterprises 2014-10-23 11:39:33 +11:00
Rob Harrington
5a837226a4 Route set_sells through put rather than post 2014-10-23 11:38:51 +11:00
Rohan Mitchell
ab76c66b68 Admin can update order cycles with simple interface 2014-10-23 11:38:15 +11:00
Rohan Mitchell
f7c1340f99 Admin can view an order cycle in the simple edit form 2014-10-23 11:08:27 +11:00
summerscope
2f045203ab Styling welcome page WIP 2014-10-23 10:56:40 +11:00
summerscope
842e239893 Make selector containers anchors 2014-10-23 10:56:30 +11:00
Rob Harrington
2e0d5eb829 Adding set_sells action to enterprises 2014-10-23 10:27:53 +11:00
Rohan Mitchell
56ebe688dc Fix file naming 2014-10-23 10:22:03 +11:00
Rohan Mitchell
8b616e7d17 Add unit spec for order cycles simple create controller 2014-10-23 10:21:19 +11:00
Rohan Mitchell
2ad823a79d Fix JS specs 2014-10-23 09:39:23 +11:00
Rohan Mitchell
94e1995469 Merge branch 'master' into simple-order-cycles 2014-10-23 09:36:03 +11:00
Rohan Mitchell
f74ec03cef Rename 2014-10-23 09:26:55 +11:00
Rohan Mitchell
66e13d40f4 Select all works on simple order cycles interface 2014-10-22 19:17:28 +11:00
Rob Harrington
f60a9d7bd5 Fiddling with styling 2014-10-22 19:13:17 +11:00
Rohan Mitchell
d47db903fb Add basic styling to simple order cycle interface 2014-10-22 19:12:51 +11:00
Rob Harrington
262972a911 Adding basic angular to welcome form 2014-10-22 19:02:39 +11:00
Rob Harrington
fef97314cb Adding basic layout of welcome page for new users 2014-10-22 18:26:18 +11:00
Rafael Schouten
069b9ce91d fix email length validation spec 2014-10-22 17:49:44 +11:00
Rohan Mitchell
3e61aa7267 Simple interface remove coordinator fee 2014-10-22 17:26:22 +11:00
Rafael Schouten
69614d6cf1 fix accordion jumps 2014-10-22 17:23:06 +11:00
Rohan Mitchell
28352be729 Save pickup time and instructions 2014-10-22 17:17:05 +11:00
Rohan Mitchell
549ef4b79d When saving an OC from the simple interface, include outgoing variants 2014-10-22 17:08:16 +11:00
Rohan Mitchell
8fb95769bf Fix tested values in spec 2014-10-22 17:07:45 +11:00
Rob Harrington
7113875a45 Adding welcome page to overview controller 2014-10-22 16:49:32 +11:00
Rob Harrington
8120023094 Fixing indentation 2014-10-22 16:33:43 +11:00
Rob Harrington
82d33332ab Adding shop_trial_start_date column to enterprises 2014-10-22 16:11:51 +11:00
Rob Harrington
ecaa2e6a51 Pull out override of 'visible' flag in enterprise serialiser 2014-10-22 15:53:25 +11:00
Rob Harrington
45ed3a4cff Only pushes activated enterprises through to the frontend 2014-10-22 15:39:49 +11:00
Rafael Schouten
2b86647281 Merge branch 'master' into bugfix 2014-10-22 15:35:00 +11:00
Rafael Schouten
96ff387d1f fix navigation check on submission 2014-10-22 15:34:31 +11:00
Rob Harrington
565d6739b3 Add 'activated' scope to enterprises 2014-10-22 15:13:52 +11:00
Rafael Schouten
a53cbb677d fix report typos 2014-10-22 14:55:01 +11:00
Rafael Schouten
afa6119ec1 better coverage for enterprise abilities, hide products from non producers 2014-10-22 14:53:20 +11:00
Rafael Schouten
175e430a2b uss oop for nav check 2014-10-22 14:51:17 +11:00
Rob Harrington
6798d394bb Use unspecified rather than unconfirmed 2014-10-22 14:50:22 +11:00
Rob Harrington
7ff4306991 Adding 'unspecified' option to 'sells' on Enterprise 2014-10-22 13:13:21 +11:00
Rob Harrington
3d938b3450 Shifting dashboard rendering from partials to templates 2014-10-22 12:30:07 +11:00
Rob Harrington
8bf472e970 Split dashboard into single and multiple enterprise views 2014-10-22 12:21:25 +11:00
Rohan Mitchell
b75af8d9ff Fix sells column coming out all 'none' 2014-10-22 10:49:23 +11:00
Rohan Mitchell
4308f7d09c Revert "use sql for migration"
This reverts commit fec8f08966.
2014-10-22 09:43:10 +11:00
Rafael Schouten
89ce4ba632 Merge branch 'master' into bugfix
Conflicts:
	app/models/enterprise.rb
2014-10-21 08:51:23 +11:00
Rafael Schouten
fec8f08966 use sql for migration 2014-10-18 16:17:29 +11:00
Rafael Schouten
78b0e02ffe Merge branch 'master' of https://github.com/openfoodfoundation/openfoodnetwork 2014-10-18 16:03:04 +11:00
Rafael Schouten
9e0f8100d9 only producers have product permissions 2014-10-18 08:28:08 +11:00
Rafael Schouten
08cd273be3 Merge branch 'migrate_ent_types' into bugfix
Conflicts:
	app/models/spree/ability_decorator.rb
2014-10-18 07:37:41 +11:00
Rafael Schouten
2a7dd8b8f1 update ability specs for reports 2014-10-18 06:53:38 +11:00
Rafael Schouten
b71a40ae6d show all permitted enterprises in order cycle summery 2014-10-18 03:26:57 +11:00
Rafael Schouten
87cc1d6217 create db/backup folder if it dosnt exist 2014-10-18 01:43:19 +11:00
Rafael Schouten
577cb06371 make navCallback actually versatile 2014-10-18 01:42:29 +11:00
Rob Harrington
361116a9ec Explicitly set confirmed_at for unconfirmed enterprise 2014-10-17 18:31:35 +11:00
Rob Harrington
cae8d566df Explicit confirmed_at to ensure that confirmation emails are sent 2014-10-17 17:49:18 +11:00
Rob Harrington
f499cc375b Adding confirmed_at to enterprise factory 2014-10-17 17:32:27 +11:00
Rob Harrington
338ba74652 Only show enterprise partial when no enterprises exist 2014-10-17 17:15:49 +11:00
Rob Harrington
5b3ff9160d Fix Registration spec 2014-10-17 17:15:16 +11:00
Rohan Mitchell
deedafde9a WIP: Simple order cycle form loads and displays correct info 2014-10-17 16:55:55 +11:00
Rohan Mitchell
d8b648d531 Extract name and timing form from order cycles 2014-10-17 16:51:03 +11:00
Rohan Mitchell
078d2bac11 Extract factories from order cycles admin angular 2014-10-17 16:50:16 +11:00
Rob Harrington
e24a774d54 Adding schema 2014-10-17 16:16:17 +11:00
Rob Harrington
4d078feea2 Add default scope to devise to stop it from checking other devise enabled models (in this case :enterprise) 2014-10-17 16:12:51 +11:00
Rohan Mitchell
f060da9c8d Rename angular app order_cycle -> admin.order_cycles 2014-10-17 14:13:27 +11:00
Rob Harrington
b2565991e6 Merge branch 'master' into reg_and_ent_types 2014-10-17 12:33:21 +11:00
Rob Harrington
eda0b16a5f Make state abbreviations upper case 2014-10-17 12:29:51 +11:00
Rob Harrington
e9a3f8ce91 Require user to choose producer or not 2014-10-17 12:29:51 +11:00
Rob Harrington
a6bc9e66f6 Only send one enterprise creation confirmation email 2014-10-17 12:29:51 +11:00
summerscope
b671543a95 Style and make pretty the finished step of profile creation 2014-10-17 12:25:04 +11:00
summerscope
4abc59f66d Change styling on the enterprise name because we dont know what type it is yet 2014-10-17 12:02:21 +11:00
summerscope
4aa2aa5aee Tweaking layout, text, styling for registration box 2014-10-17 11:56:25 +11:00
summerscope
2c5208ce6b Change ent type page, simplify! 2014-10-17 11:17:53 +11:00
Rob Harrington
81715aaf5d Remove unrequired store registration action 2014-10-17 11:01:39 +11:00
Rob Harrington
c4d47ccc20 Change enterprise attributes defined in reg controller 2014-10-17 11:01:38 +11:00
Rohan Mitchell
694dd0c329 Enterprise user selling own produce only sees simple order cycle listing 2014-10-17 10:52:36 +11:00
summerscope
4884734ab5 Align Continue buttons right consistently 2014-10-17 10:43:19 +11:00
Rob Harrington
28807d4f4d Merge migrate_ent_types into reg 2014-10-17 10:20:48 +11:00
Rob Harrington
6a6f603754 Correct syntax for update column 2014-10-17 10:03:34 +11:00
Rafael Schouten
2e3cb171a3 don't remove indexes after you remove one of their columns! 2014-10-17 08:22:52 +11:00
Rafael Schouten
b853f908d3 bugfix email dummy 2014-10-17 08:08:10 +11:00
Rafael Schouten
1a40c83a48 update chema with indexes 2014-10-17 07:59:51 +11:00
Rafael Schouten
9536b3e764 add navigation directive default 2014-10-17 07:58:08 +11:00
Rafael Schouten
f1280a31a6 Merge branch 'reports' into bugfix 2014-10-17 07:41:30 +11:00
Rafael Schouten
245c1eb305 use a directive for navigation check to attach it to the page instead of the controller 2014-10-17 07:40:08 +11:00
Rafael Schouten
bda1eafcec add migrating for dummy emails 2014-10-17 06:37:22 +11:00
Rafael Schouten
dd3101f27a remove some bangs 2014-10-17 06:14:39 +11:00
Rafael Schouten
45b0581b7b Merge branch 'master' into bugfix 2014-10-17 05:35:10 +11:00
Rafael Schouten
3234bc328f Merge branch 'master' into reports 2014-10-17 04:02:29 +11:00
Rafael Schouten
4defb38cf4 update karma config 2014-10-17 04:01:36 +11:00
Rafael Schouten
1150e69500 fix visible bug 2014-10-17 03:59:48 +11:00
Rob Harrington
c7145f8dcd Merge branch 'reg' of github.com:openfoodfoundation/openfoodnetwork into reg 2014-10-16 16:53:34 +11:00
Rafael Schouten
6fd9741daf use build instead of create, and reorganise code 2014-10-16 16:51:09 +11:00
Rafael Schouten
a1d74649f3 rename spec and clear todo 2014-10-16 16:50:19 +11:00
Rafael Schouten
f145db46f1 use self.x 2014-10-16 16:49:49 +11:00
Rafael Schouten
1b0000a1de use bangs 2014-10-16 16:48:01 +11:00
summerscope
8d01bb7ebf Pretty responsive email template!!!!!!!! 2014-10-16 16:45:15 +11:00
Rafael Schouten
425105174e return space remover 2014-10-16 16:26:50 +11:00
Rafael Schouten
c5afd8cebf move visible filter to pages, and use category 2014-10-16 16:26:50 +11:00
Rafael Schouten
027189ac3c rename check methods 2014-10-16 16:26:49 +11:00
Rafael Schouten
f0a3296e52 change enterprise category name ans use symbols instead of strings 2014-10-16 16:26:49 +11:00
Rob Harrington
7db68795a4 Redirect to admin root after confirmation 2014-10-16 16:06:54 +11:00
Rafael Schouten
2e8417d9e8 bugfix migration and add indexes 2014-10-16 16:05:07 +11:00
Rohan Mitchell
0e03b5f209 Admin can change the format that Spree::Images are stored/served in 2014-10-16 12:41:11 +11:00
Rohan Mitchell
7e23479f3a Consistency 2014-10-16 12:08:12 +11:00
Rob Harrington
a6480e6831 Merge in enterprise confirmation 2014-10-16 11:52:10 +11:00
Rob Harrington
63e50dc88c Fiddle with alert styling 2014-10-16 11:34:06 +11:00
Rafael Schouten
fd7191f476 add missing orders_and_distributors perm 2014-10-16 05:26:38 +11:00
Rafael Schouten
9343c3608b allow supplier enterprise manager to see bulk coop reports 2014-10-16 04:29:33 +11:00
Rafael Schouten
1577c01a77 add reports abilities specs 2014-10-16 04:29:33 +11:00
Rafael Schouten
46df14c0d9 refator reports controller a little 2014-10-16 04:29:33 +11:00
Rafael Schouten
e44fed2ff0 add authorization to reports listings on index page 2014-10-16 04:29:33 +11:00
Rafael Schouten
0d715ce615 split report permissions 2014-10-16 04:29:16 +11:00
Rob Harrington
96878f5dcb Don't require confirmation for enterprises where the email address has already been confirmed for another enterprise 2014-10-15 17:22:56 +11:00
Rob Harrington
20cb11a298 Update registration spec 2014-10-15 16:28:52 +11:00
Rob Harrington
0940af6b66 Remove bad pry 2014-10-15 16:21:11 +11:00
Rob Harrington
e0e8ba814f Show explanation of confirm process on final page of registration 2014-10-15 16:20:45 +11:00
Rob Harrington
c59662758c Add alerts for unconfirmed enterprises to overview page 2014-10-15 15:46:21 +11:00
Rob Harrington
c76a3815c0 Add unconfirmed scope 2014-10-15 15:45:47 +11:00
Rob Harrington
1bdc55cb33 Adding confirmed scope to enterprises 2014-10-15 13:03:39 +11:00
Rob Harrington
56f4d5af0f Visibility in the front end is contingent upon enterprise being confirmed 2014-10-15 12:27:55 +11:00
Rob Harrington
6e699b2e8b Mailer tests 2014-10-15 11:52:04 +11:00
Rob Harrington
908c242d36 Confirmation email when creating enterprise 2014-10-15 10:48:05 +11:00
Rafael Schouten
5e41865871 add utils angular module and navigation check factory 2014-10-14 00:26:04 +11:00
Rafael Schouten
5dd9879b96 validate description max lenth 2014-10-12 21:57:01 +11:00
Rafael Schouten
01c179856a set maxlength for short description field 2014-10-12 21:19:59 +11:00
Rafael Schouten
9a6958573a Merge branch 'master' into bugfix
Conflicts:
	app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee
2014-10-12 21:19:02 +11:00
summerscope
a4e72f6fbc Making the header more semantically meaningful for HTML5. Add in row to make spacing consistent. Steps bar moves to top 2014-10-10 18:20:38 +11:00
summerscope
89a51bf1da Adjustments to layout, responsive logic, simplify column structure 2014-10-10 18:19:42 +11:00
summerscope
d4318263f6 Registration modals styling WIP 2014-10-10 18:18:33 +11:00
Rob Harrington
b8b19368df WIP: Making enterprise emails confirmable 2014-10-10 16:54:38 +11:00
Rohan Mitchell
d5ea2a0206 Make Enterprise and EnterpriseGroup promo images jpg format 2014-10-10 15:40:05 +11:00
Rob Harrington
9b275cc5f0 WIP: Shuffling around order of cards in registration 2014-10-09 17:26:31 +11:00
Rob Harrington
d1e3f74c03 Add loading gif to image uploaders 2014-10-09 15:56:54 +11:00
Rob Harrington
fc3a132c12 Closing auth dialog on pages other than home returns the user to home 2014-10-09 13:46:32 +11:00
Rob Harrington
31c4aad9e1 JS for closing alerts works 2014-10-09 13:21:30 +11:00
Rob Harrington
49c8e2f8cb Remove used styling for inline flash 2014-10-09 13:16:09 +11:00
Rob Harrington
83f9867632 Move registration login into own folder, reinstate ofn-inline-alert 2014-10-09 13:15:19 +11:00
Rob Harrington
65ac9d7226 Merge branch 'master' into reg 2014-10-09 09:26:17 +11:00
Rafael Schouten
e7b847542f bugfix tab selection 2014-10-08 01:59:56 +11:00
Rafael Schouten
20a94b4365 Merge branch 'master' into migrate_ent_types
Conflicts:
	app/serializers/api/admin/enterprise_serializer.rb
2014-10-07 10:52:26 +11:00
Rafael Schouten
9b6db2bff4 simplify tab selection 2014-10-07 10:49:57 +11:00
Rafael Schouten
6fc36a3e6c swap redundant producer modal for general enterprise modal 2014-10-07 10:48:04 +11:00
Rafael Schouten
e476324c60 fix for_order_cycle test 2014-10-07 00:22:45 +11:00
Rafael Schouten
ec6805f573 use shared partial for no results 2014-10-06 23:51:19 +11:00
Rafael Schouten
7805d46743 more angular documentation 2014-10-06 23:20:43 +11:00
Rafael Schouten
881e82e825 add some angular documentation 2014-10-06 22:59:06 +11:00
Rafael Schouten
2ae325455a fix producer taxon filtering bug 2014-10-06 22:58:48 +11:00
Rafael Schouten
922e335e83 add is_hub to model 2014-10-06 15:42:23 +11:00
Rafael Schouten
cc6af82823 move reports abilitiy to can manage products block, producers need to use this too 2014-10-06 15:40:41 +11:00
Rafael Schouten
76e170eb3a move icons into cached, for now 2014-10-06 10:44:49 +11:00
Rafael Schouten
c495e967cb bugfix and extend angular enterprise spec 2014-10-06 01:36:18 +11:00
Rafael Schouten
017d6b1273 move for order cycles permission, for now, but needs review 2014-10-06 01:35:46 +11:00
Rafael Schouten
9eb770aed7 fix sidebar show/hide 2014-10-05 01:44:40 +10:00
Rafael Schouten
2f76a7ba80 add comment for hub sells own case 2014-10-05 01:44:12 +10:00
Rafael Schouten
58c39b340d remove duplicate default value assignment 2014-10-05 01:43:50 +10:00
Rafael Schouten
f0c9e7cd44 fix for tests, remove open in new tab 2014-10-04 13:12:36 +10:00
Rafael Schouten
f3fc70ebf0 Merge branch 'master' into raf_bugfix
Conflicts:
	app/assets/stylesheets/admin/openfoodnetwork.css.scss
2014-10-04 12:51:55 +10:00
Rafael Schouten
884c111240 fix failing tests 2014-10-04 11:56:35 +10:00
Rafael Schouten
698126edb2 specifify visible enterprises in tests 2014-10-04 01:01:04 +10:00
Rafael Schouten
b3482a087b separate enterprises from visible enterprises 2014-10-04 01:00:37 +10:00
Rafael Schouten
a552fb18da style profile check 2014-10-04 01:00:02 +10:00
Rafael Schouten
2670d2b0ad cleanup serializer 2014-10-04 00:59:41 +10:00
Rafael Schouten
01063367c4 clickable show profiles label 2014-10-04 00:59:17 +10:00
Rafael Schouten
a0494b136f test that email is validated 2014-10-03 17:32:04 +10:00
Rafael Schouten
c088c47a49 add email to enterprise params 2014-10-03 17:31:46 +10:00
Rafael Schouten
77e354f9f6 Merge branch 'master' into wys 2014-10-03 16:47:11 +10:00
Rafael Schouten
dee471b1c7 move text angular files 2014-10-03 16:43:56 +10:00
Rafael Schouten
bdd9e19efe specs - add text angular dep and long descrioption provider 2014-10-03 16:42:37 +10:00
Rafael Schouten
34ceb9c226 style text box 2014-10-03 16:06:15 +10:00
Rafael Schouten
bb24e1ce88 sanitize long_description html before injection 2014-10-03 16:06:04 +10:00
Rafael Schouten
e75a964703 Merge branch 'master' into raf_bugfix 2014-10-03 14:26:08 +10:00
Rafael Schouten
8805079faa use attubutes instead of save! 2014-10-03 14:03:34 +10:00
Rafael Schouten
7313aecd19 add route checking, not working yet... 2014-10-03 12:19:58 +10:00
Rafael Schouten
929839cb9f hide configuration on 2014-10-03 11:46:00 +10:00
Rafael Schouten
d707ba1a70 remove nokugiri from gemfile.lock 2014-10-02 19:08:37 +10:00
Rafael Schouten
ff4f8f63af Merge branch 'master' into raf_bugfix
Conflicts:
	app/views/spree/order_mailer/confirm_email.text.haml
2014-10-02 19:06:30 +10:00
Rafael Schouten
b3520c4385 Bugfix for specs 2014-10-02 16:49:32 +10:00
Rafael Schouten
526ab8b80f use is_distributor bool 2014-10-02 16:28:01 +10:00
Rafael Schouten
f29898886d return basic css and js for oldskool login that somehow still exists 2014-10-02 13:24:59 +10:00
Rafael Schouten
1e84e4fa85 own and any instead of single and full for abilities 2014-10-02 13:11:19 +10:00
Rafael Schouten
ce9b132ab5 only show visible enterprises 2014-10-02 13:10:46 +10:00
Rob Harrington
5f4b2a752b Product controller loads correct data for create and update actions 2014-10-02 12:32:26 +10:00
Rafael Schouten
4c1fc5671f Minor fixes 2014-10-02 10:43:17 +10:00
Rafael Schouten
e62e87549a commit this elsewhere 2014-10-02 10:41:43 +10:00
Rafael Schouten
62f7114fa1 Merge branch 'cleanup' into migrate_ent_types
Conflicts:
	app/views/home/_hubs.html.haml
2014-10-02 10:02:08 +10:00
Rafael Schouten
47dc001735 merge has_shopfront and is_distibutor 2014-10-01 20:27:53 +10:00
Rafael Schouten
3877bed62b use enterprise modal 2014-10-01 18:51:49 +10:00
Rafael Schouten
ccdcf16cec rename file 2014-10-01 18:47:50 +10:00
Rafael Schouten
54b138b2cc add transclusion to modal directive by default 2014-10-01 18:47:22 +10:00
Rafael Schouten
412bf8f638 cleanup gemfile 2014-10-01 17:16:09 +10:00
Rafael Schouten
b647f9382f revert included file 2014-10-01 17:11:00 +10:00
Rafael Schouten
56a9658b14 update ability spec 2014-10-01 16:55:41 +10:00
Rafael Schouten
47991f192e tweak migration 2014-10-01 16:49:47 +10:00
Rafael Schouten
4fde0ad2d7 Merge branch 'master' into migrate_ent_types 2014-10-01 16:11:20 +10:00
Rafael Schouten
1ec4f2e456 Merge branch 'ent_types_frontend' into migrate_ent_types
Conflicts:
	app/models/enterprise.rb
2014-10-01 16:10:43 +10:00
Rafael Schouten
3a14a26bc6 refactor wysiwyg 2014-10-01 16:07:10 +10:00
Rafael Schouten
fa41f6dc40 add rollback to migration 2014-10-01 13:02:21 +10:00
Rob Harrington
5497f229e1 Ignoring enterprise ownership before_validations when no owner set 2014-10-01 11:49:46 +10:00
Rafael Schouten
206c8da0ba remove unused css* 2014-09-30 23:53:45 +10:00
Rafael Schouten
a2dff2305f space in order confirm mailer 2014-09-30 19:39:56 +10:00
Rafael Schouten
726340fc86 configure textAngular on enterprise edit page 2014-09-30 18:20:45 +10:00
Rafael Schouten
823923f828 add textAngular javascript 2014-09-30 15:09:43 +10:00
Rafael Schouten
a49991c696 set abilities tests to pending, need to discuss further 2014-09-28 22:55:49 +10:00
Rafael Schouten
dc7c9ea272 commit updated schema 2014-09-28 22:37:26 +10:00
Rafael Schouten
58f13a3e06 update migration 2014-09-28 12:57:27 +10:00
Rafael Schouten
5c0d846643 bugfix sells and is_distributor specs and code 2014-09-28 11:55:46 +10:00
Rafael Schouten
b821107c27 bugfix migration ad specs 2014-09-27 18:14:10 +10:00
Rafael Schouten
beb85e862a get type > sells migration mostly working 2014-09-27 15:21:27 +10:00
Rafael Schouten
dee869a273 move checks and links in sidebars 2014-09-26 17:58:00 +10:00
summerscope
0c99007323 Tweak the modal styling for register modals 2014-09-26 17:45:15 +10:00
summerscope
c91d707806 Merge branch 'master' into ent_types_frontend 2014-09-26 15:07:30 +10:00
summerscope
3adf571c1f Style the modal headers 2014-09-26 14:55:41 +10:00
summerscope
c43b8abcbc Changing the markup to give a class where is a producer 2014-09-26 14:55:41 +10:00
Rafael Schouten
3406f926fc fix enterprsie model logic 2014-09-26 14:48:37 +10:00
Rafael Schouten
e480d3a135 rearrange admin sidebars 2014-09-26 13:06:29 +10:00
summerscope
c1460afaee Tweak language around the long description 2014-09-26 12:07:58 +10:00
summerscope
a73541da71 Change styling for register modals 2014-09-26 12:07:38 +10:00
Rafael Schouten
ceb978783c update missed taxon selector filter 2014-09-26 00:25:19 +10:00
Rafael Schouten
4b576d1590 refactor enterprise specs 2014-09-26 00:15:33 +10:00
Rafael Schouten
04c5dff497 fixup merge 2014-09-25 19:47:00 +10:00
Rafael Schouten
55f4415c0d Merge branch 'master' into cleanup
Conflicts:
	app/assets/javascripts/darkswarm/services/hubs.js.coffee
	app/views/home/_hubs.html.haml
	app/views/producers/_filters.html.haml
	app/views/producers/index.html.haml
2014-09-25 19:42:20 +10:00
Rafael Schouten
6069127733 validate contact email 2014-09-25 15:16:50 +10:00
Rafael Schouten
afd0f76d9e Merge branch 'master' into bugfix 2014-09-25 14:23:46 +10:00
Rafael Schouten
bab9123ca8 delete unused javascript 2014-09-25 14:01:06 +10:00
Rafael Schouten
096324cf5e bugfix filters 2014-09-25 13:46:08 +10:00
Rafael Schouten
0e2774882f dry enterprise angular 2014-09-25 13:06:02 +10:00
Rafael Schouten
3775cd29cb generalise search filter to any enterprise 2014-09-25 11:34:49 +10:00
Rafael Schouten
a058af8211 open products in new tab 2014-09-24 17:00:12 +10:00
Rafael Schouten
139da3ac7a outline inputs with errors 2014-09-24 16:59:57 +10:00
225 changed files with 2916 additions and 3385 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 162 KiB

View File

@@ -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, */*"

View File

@@ -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 .

View File

@@ -43,6 +43,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", [
$scope.currentFilters = []
$scope.limit = 15
$scope.productsWithUnsavedVariants = []
$scope.query = ""
$scope.initialise = ->
authorise_api_reponse = ""

View File

@@ -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)

View File

@@ -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

View File

@@ -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"])

View File

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

View File

@@ -1,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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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
})

View File

@@ -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
})

View File

@@ -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
})

View File

@@ -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)

View File

@@ -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

View File

@@ -0,0 +1 @@
angular.module("admin.utils", [])

View File

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

View File

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

View File

@@ -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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
Darkswarm.directive "ofnInlineAlert", ->
restrict: 'A'
scope: true
link: (scope, elem, attrs) ->
scope.visible = true
scope.close = ->
scope.visible = false

View File

@@ -1,6 +0,0 @@
Darkswarm.directive "ofnInlineFlash", ->
restrict: 'E'
controller: ($scope) ->
$scope.visible = true
$scope.closeFlash = ->
$scope.visible = false

View File

@@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,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 = "/"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,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 => "#"} &times;
.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 => "#"} &times;
.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()" } } &times;
.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" }

View File

@@ -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')" } }
&nbsp;
%input.button.primary{ type: "submit", value: "Continue" }

View File

@@ -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' } } &nbsp; Display phone in profile
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('address')" } }
&nbsp;
%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" }

View File

@@ -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 &amp;/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 &amp;/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" }

View File

@@ -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 &gt;
.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 &gt;
%a.button.primary{ type: "button", href: "/" } Open Food Network home &gt;

View File

@@ -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')" } }
&nbsp;
%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')" } }
&nbsp;
%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" }

View File

@@ -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...

View File

@@ -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...

View File

@@ -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')" } }

View File

@@ -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()" } }

View File

@@ -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')" } }
&nbsp;
%input.button.primary{ type: "submit", value: "Continue" }
%input.button.primary.right{ type: "submit", value: "Continue" }

View File

@@ -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 }}

View 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
&nbsp;
%p Producers make yummy things to eat &amp;/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" }

View 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

View File

@@ -9,6 +9,7 @@
*= require admin/spree_promo
*= require shared/jquery-ui-timepicker-addon
*= require shared/textAngular.min
*= require_self
*= require_tree .

View 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

View File

@@ -0,0 +1,8 @@
#trial_progress_bar
position: fixed
bottom: 0px
width: 100%
padding: 8px 10px
font-weight: bold
background-color: #5498da
color: white

View 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

View File

@@ -156,4 +156,4 @@ div.dashboard_item
background-color: #9fc820
&.bottom
border-radius: 0px 0px 6px 6px
padding: 15px 15px
padding: 15px 15px

View File

@@ -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;
}
}
}

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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/

View File

@@ -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/

View 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}

View File

@@ -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/

View File

@@ -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