Compare commits

...

109 Commits

Author SHA1 Message Date
Pau Pérez Fabregat
be19d50639 Merge pull request #4768 from openfoodfoundation/transifex
Transifex
2020-02-06 11:11:23 +01:00
Transifex-Openfoodnetwork
0ceb8ab6c4 Updating translations for config/locales/ca.yml 2020-02-06 21:09:16 +11:00
Pau Pérez Fabregat
e387c7db83 Merge pull request #4548 from luisramos0/improve_truncate_data
Improve truncate data process
2020-02-06 11:01:36 +01:00
Pau Pérez Fabregat
d5df48f3c0 Merge pull request #4737 from openfoodfoundation/transifex
Transifex
2020-02-06 11:00:46 +01:00
Pau Pérez Fabregat
c9abdac2e0 Merge pull request #4722 from mkllnk/code-climate-rubocop
Bump Code Climate's Rubocop version to their latest
2020-02-06 10:32:46 +01:00
Transifex-Openfoodnetwork
ff08d9f210 Updating translations for config/locales/nb.yml 2020-02-06 09:39:52 +11:00
Luis Ramos
9313a57d19 Merge pull request #4511 from luisramos0/backend_ctrl_search
Bring spree_backend search controller to OFN
2020-02-05 15:54:30 +00:00
luisramos0
b0f2e01c70 Delete extra inventory_units that are for some unknown reason connected to shipments of orders to delete but not to orders to delete 2020-02-05 16:30:14 +11:00
Maikel
747be81aec Link to new release template 2020-02-05 15:21:26 +11:00
Maikel
fd124daf50 Add task to notify instance managers of upcoming changes 2020-02-05 14:58:57 +11:00
Transifex-Openfoodnetwork
ef33d27e6c Updating translations for config/locales/en_FR.yml 2020-02-05 06:55:27 +11:00
Transifex-Openfoodnetwork
3a01e00d7b Updating translations for config/locales/fr.yml 2020-02-05 06:51:14 +11:00
Luis Ramos
81103f3f71 Merge pull request #4742 from CSCI-462-01-2020/Issue4109
Edit new_resource partial
2020-02-04 19:44:16 +00:00
Luis Ramos
a8b48a561f Merge pull request #4733 from lin-d-hop/master
Fixing incorrect payment and balance calculation
2020-02-04 18:11:48 +00:00
Luis Ramos
c7038f6ac9 Merge pull request #4620 from luisramos0/spree_backend_css
Bring basic CSS rules from spree backend
2020-02-04 18:06:15 +00:00
Luis Ramos
ea75714561 Merge pull request #4635 from luisramos0/main_app_routes
Replace use of spree.root_path and root_url with main_app.root_path and main_app.root_url
2020-02-04 16:02:48 +00:00
luisramos0
b7d19dd34c Remove unused route from Spree.routes 2020-02-04 14:55:34 +00:00
luisramos0
44d1b3f00c Remove unused search/users controller action 2020-02-04 14:55:34 +00:00
luisramos0
f8376c0aeb Remove unused route search_customer_addresses 2020-02-04 14:55:34 +00:00
luisramos0
88464d58c2 Fix some rubocop issues and extract ransack hash to reduce repetition 2020-02-04 14:55:34 +00:00
luisramos0
962779bba1 Merge search controller with decorator 2020-02-04 14:54:51 +00:00
luisramos0
1ae73dd6ae Add search_controller from spree_backend so that we can now merge it with the OFN's decorator 2020-02-04 14:54:51 +00:00
luisramos0
f48ab57782 Add explicit css import statements where they are needed 2020-02-04 14:52:44 +00:00
luisramos0
8b6ebfb351 Add imports for new css files from spree_backend 2020-02-04 14:52:44 +00:00
luisramos0
9c0788c3e0 Bring shared css rules from spree_backend 2020-02-04 14:52:17 +00:00
luisramos0
f61258d0b4 Bring components css from spree_backend
pagination and navigation rules were merged
2020-02-04 14:52:17 +00:00
luisramos0
289f62f115 Bring and require date picker css from spree_backend 2020-02-04 14:52:17 +00:00
luisramos0
c3a98d5a4f Bring css dependencies from spree_backend
These dependencies are in spree_core so we dont need to bring them to ofn right now
2020-02-04 14:52:17 +00:00
Luis Ramos
d8374e9caa Merge pull request #4614 from luisramos0/base_admin_js
Bring some basic js functions and dependencies from spree_backend
2020-02-04 14:48:38 +00:00
luisramos0
0648f23e94 Move css dependencies to specific css files and add some required dependencies from spree_backend 2020-02-04 14:47:51 +00:00
luisramos0
e37cb2d63f Remove underscope from select2 css file name 2020-02-04 14:47:51 +00:00
luisramos0
ee64238bdd Add jquery.adaptivemenu require but commeent out the activation for now because it is already called in spree_backend
This can be reverted when spree_backend is removed
2020-02-04 14:47:51 +00:00
luisramos0
d3130e111f Remove on click events
These events can only be added to OFN when spree_backend is removed otherwise the evetns will be registered twice
2020-02-04 14:47:51 +00:00
luisramos0
93f4eee887 Make newly imported js files compatible with the karma build 2020-02-04 14:47:51 +00:00
luisramos0
408ada9097 Remove unnecessary build exception 2020-02-04 14:47:51 +00:00
luisramos0
e14ebd9503 Add required variables from spree_backend 2020-02-04 14:47:51 +00:00
luisramos0
289b99c30e Bring and require equalize from spree_backend 2020-02-04 14:47:26 +00:00
luisramos0
f85c36a17e Bring and require select2 from spree_backend 2020-02-04 14:47:26 +00:00
luisramos0
4715df3258 Bring and require jquery.horizontalNav.js from spree_backend 2020-02-04 14:47:26 +00:00
luisramos0
b20be101cc Bring and require spin from spree_backend and respective progress indicator js and css 2020-02-04 14:47:26 +00:00
luisramos0
d424987587 Bring and require jquery.vAlign.js from spree_backend 2020-02-04 14:47:26 +00:00
luisramos0
a0575430dd Require spree.js from spree_core for some basic functions like Spree.url 2020-02-04 14:46:57 +00:00
luisramos0
c1e6344b18 Merge spree js function and override 2020-02-04 14:46:57 +00:00
luisramos0
ed0198382f Bring spree_backend admin.js.erb, rename it to base.js.erb and remove requires that are not used in ofn 2020-02-04 14:46:57 +00:00
blainebillings
577fb88843 Move Create and Cancel References to Actions Namespace 2020-02-04 09:39:01 -05:00
Pau Pérez Fabregat
2b879221b2 Merge pull request #4756 from kristinalim/fix/4489-flaky_spec_for_editing_oc
4489 Flaky spec when editing outgoing exchanges in OC
2020-02-04 15:38:37 +01:00
blainebillings
22db2e99f0 Merge branch 'Issue4109' of https://github.com/CSCI-462-01-2020/openfoodnetwork into Issue4109 2020-02-04 09:38:19 -05:00
blainebillings
ef4aa488c3 Moves Create and Cancel References to Actions Namespace 2020-02-04 09:34:28 -05:00
Pau Pérez Fabregat
57775f49bc Merge pull request #4739 from openfoodfoundation/dependabot/bundler/rack-mini-profiler-1.1.6
Bump rack-mini-profiler from 1.1.4 to 1.1.6
2020-02-04 15:29:20 +01:00
Pau Pérez Fabregat
e8a12d9897 Merge pull request #4738 from openfoodfoundation/dependabot/bundler/oj-3.10.2
Bump oj from 3.10.1 to 3.10.2
2020-02-04 15:28:40 +01:00
Pau Pérez Fabregat
f3b8d5b868 Merge pull request #4741 from openfoodfoundation/dependabot/bundler/bugsnag-6.13.0
Bump bugsnag from 6.12.2 to 6.13.0
2020-02-04 15:28:00 +01:00
Pau Pérez Fabregat
246235b921 Merge pull request #4667 from Matt-Yorkley/rails-4-prep
Rails 4 prep
2020-02-04 15:20:28 +01:00
Luis Ramos
0ded41afee Merge pull request #4513 from luisramos0/backend_ctrl_orders
Bring spree_backend orders controller to OFN
2020-02-04 11:51:54 +00:00
luisramos0
d32e106bf0 Add partials needed in the orders edit page 2020-02-04 11:51:13 +00:00
luisramos0
bbb3748d3c Simplify orders events logic 2020-02-04 11:51:13 +00:00
luisramos0
08dd992344 Merge orders_helper with decorator 2020-02-04 11:51:13 +00:00
luisramos0
914244a1ee Bring orders helper from spree_backend 2020-02-04 11:51:13 +00:00
luisramos0
e5f089610c Bring admin orders routes from spree_backend 2020-02-04 11:51:13 +00:00
luisramos0
6e26841817 Fix load_order before filter and remove unused open and close adjustments actions 2020-02-04 11:50:44 +00:00
luisramos0
ab60c4a9dd Remove unnecessary index action override because this is no longer a decorator
Remove useless todo comment
2020-02-04 11:50:44 +00:00
luisramos0
7009cd89e0 Fix rubocop issues in customer details controller and update rubocop manual todo accordingly 2020-02-04 11:50:44 +00:00
luisramos0
b93af37ea9 Merge customer details decorator with controller 2020-02-04 11:50:03 +00:00
luisramos0
76b6a85509 Merge spree/admin/orders_controller and its decorator and fix a few rubocop issues 2020-02-04 11:50:03 +00:00
luisramos0
a1d4b4ee98 Add orders_controller from spree_backend so that we can now merge it with the OFN's decorator 2020-02-04 11:50:03 +00:00
luisramos0
51bca7ce2f Add customer_details_controller from spree_backend so that we can now merge it with the OFN's decorator 2020-02-04 11:50:03 +00:00
Luis Ramos
70147f908a Merge pull request #4611 from luisramos0/taxonomies_js
Bring js code to make taxonomies admin work without spree_backend
2020-02-04 11:47:27 +00:00
Luis Ramos
c4bf4f001f Merge pull request #4509 from luisramos0/backend_ctrl_payments
Bring spree_backend payments controller to OFN
2020-02-04 11:46:23 +00:00
Matt-Yorkley
7d71f21753 Add frozen_string_literal comment to new class 2020-02-04 11:11:24 +01:00
Matt-Yorkley
285c78a5e4 Remove use of #pluck and ensure subquery does not include all columns 2020-02-04 11:10:13 +01:00
luisramos0
9a2ad16926 Make explicit the dependency to font-awesome css rules 2020-02-04 09:34:59 +00:00
luisramos0
afec21eb3d Move imports to where they are needed 2020-02-04 09:34:59 +00:00
luisramos0
651ee720c6 Remove underscore from new jstree css file 2020-02-04 09:34:40 +00:00
luisramos0
2e6c5e1fad Add dependencies from spree_backend required by jstree 2020-02-04 09:34:40 +00:00
luisramos0
87366ae7fc Remove usage of jConfirm so that we dont have to bring dependency jquery.alerts from spree_backend 2020-02-04 09:33:58 +00:00
luisramos0
27aea0b277 Bring js code from spree_backend to make taxons admin work 2020-02-04 09:33:58 +00:00
luisramos0
d4edc9f20d Bring jstress css from spree_backend 2020-02-04 09:33:58 +00:00
luisramos0
6c7991be75 Bring jquery.jstree from spree_backend 2020-02-04 09:33:34 +00:00
luisramos0
3f81352df5 Bring jquery.cookie from spree_backend 2020-02-04 09:33:34 +00:00
Kristina Lim
9d0e26ae28 Wait for products panel to show in outgoing exchanges feature spec 2020-02-04 16:20:47 +08:00
blainebillings
9218008530 Edit new_resource Partial 2020-02-02 11:22:54 -05:00
myersca1
f36c5b8938 Edit new_resource partial 2020-02-02 11:19:10 -05:00
dependabot-preview[bot]
67199fd2d6 Bump bugsnag from 6.12.2 to 6.13.0
Bumps [bugsnag](https://github.com/bugsnag/bugsnag-ruby) from 6.12.2 to 6.13.0.
- [Release notes](https://github.com/bugsnag/bugsnag-ruby/releases)
- [Changelog](https://github.com/bugsnag/bugsnag-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bugsnag/bugsnag-ruby/compare/v6.12.2...v6.13.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-31 19:15:09 +00:00
Transifex-Openfoodnetwork
18d17ec674 Updating translations for config/locales/fr_CA.yml 2020-02-01 04:02:53 +11:00
Transifex-Openfoodnetwork
3981ee7ec1 Updating translations for config/locales/en_CA.yml 2020-02-01 03:54:02 +11:00
dependabot-preview[bot]
25c4aed368 Bump rack-mini-profiler from 1.1.4 to 1.1.6
Bumps [rack-mini-profiler](https://github.com/MiniProfiler/rack-mini-profiler) from 1.1.4 to 1.1.6.
- [Release notes](https://github.com/MiniProfiler/rack-mini-profiler/releases)
- [Changelog](https://github.com/MiniProfiler/rack-mini-profiler/blob/master/CHANGELOG.md)
- [Commits](https://github.com/MiniProfiler/rack-mini-profiler/compare/v1.1.4...v1.1.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-30 19:28:45 +00:00
dependabot-preview[bot]
c5a6ef673c Bump oj from 3.10.1 to 3.10.2
Bumps [oj](https://github.com/ohler55/oj) from 3.10.1 to 3.10.2.
- [Release notes](https://github.com/ohler55/oj/releases)
- [Changelog](https://github.com/ohler55/oj/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/ohler55/oj/compare/v3.10.1...v3.10.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-30 19:26:07 +00:00
Transifex-Openfoodnetwork
79ba15fe9a Updating translations for config/locales/en_GB.yml 2020-01-31 03:53:48 +11:00
luisramos0
e192207f4e Fix bug in before filters migration, needs to load payment for the show action 2020-01-30 10:27:26 +00:00
lin-d-hop
baf1ecb436 Fixing incorrect payment and balance calculation
Corrections and added specs
2020-01-29 16:06:06 +00:00
Maikel Linke
ec67736dff Bump Code Climate's Rubocop version to their latest
Our used version is still higher than that.
2020-01-28 17:12:28 +11:00
luisramos0
766303b332 Add required payment_helper from spree_backend 2020-01-22 20:22:28 +00:00
luisramos0
74226fbdf8 Fix one rubocop issue and update rubocop todo manual for the new controller 2020-01-22 20:22:28 +00:00
luisramos0
dc5374e284 Merge filter_payment_methods and load_data 2020-01-22 20:21:21 +00:00
luisramos0
f6ecf57737 Make before filters easier to understand using the fact that there are only index, create, new and fire actions in this controller 2020-01-22 20:21:21 +00:00
luisramos0
940953b043 Add missing translations for payments 2020-01-22 20:21:21 +00:00
luisramos0
fbc5887fa6 Bring payments routes from spree_backend 2020-01-22 20:21:21 +00:00
luisramos0
61ce849546 Merge spree/admin/payments_controller with its decorator and fix a few rubocop issues 2020-01-22 20:21:21 +00:00
luisramos0
afddaed9fc Add empty but needed payments templates for check payment method 2020-01-22 20:21:21 +00:00
luisramos0
12158d73fa Add payments_controller from spree_backend so that we can now merge it with the OFN's decorator 2020-01-22 20:21:21 +00:00
Matt-Yorkley
5f3abbf00e Refactor BaseController 2020-01-22 12:17:23 +01:00
Matt-Yorkley
a02c58e231 Add join_table to enterprise groups relation
has_and_belongs_to_many relationships now require a join_table
2020-01-22 12:17:23 +01:00
Matt-Yorkley
59ebfb9bd4 Fix subquery errors triggered by #warn_invalid_order_cycles 2020-01-22 12:17:23 +01:00
Matt-Yorkley
57ca1d54bb Fix issue with each_serializer not being called in some cases in Rails 4. 2020-01-22 12:17:23 +01:00
luisramos0
5fccd5fe58 Add rubocop exception for application controller class length and fix one line length issue 2020-01-12 19:42:07 +00:00
luisramos0
4658b7a533 Fix rubocop issues in app/controllers/application_controller 2019-12-28 19:10:02 +00:00
luisramos0
d0f33e7c8a Avoid code in devise that is not needed and simply return the root path
This fixes a broken spec with error "No route matches {:controller=>"home"}"
2019-12-28 18:47:14 +00:00
luisramos0
55bb328d48 Prefix all calls to root_url with main_app 2019-12-28 18:46:50 +00:00
luisramos0
a8a6fce385 Prefix root_path with main_app so that ofn's route is used. The spree root path will no longer be defined when spree_backend is dropped 2019-12-28 18:45:57 +00:00
luisramos0
60677a2414 Make login nav use main_app router 2019-12-28 18:41:16 +00:00
96 changed files with 8352 additions and 426 deletions

View File

@@ -2,7 +2,7 @@ version: "2"
plugins:
rubocop:
enabled: true
channel: "rubocop-0-57"
channel: "rubocop-0-76"
config:
file: ".rubocop_styleguide.yml"
scss-lint:

View File

@@ -1,7 +1,7 @@
---
name: Release task
about: Track the process of a new release
title: ''
title: 'Release v'
labels: ''
assignees: ''
@@ -10,10 +10,13 @@ assignees: ''
Steps:
- [ ] Include translations
- [ ] Draft: https://github.com/openfoodfoundation/openfoodnetwork/releases/new <!-- replace the URL -->
- [ ] [Draft new release]
- [ ] Notify #instance-managers of user-facing changes.
- [ ] Test: https://semaphoreci.com/openfoodfoundation/openfoodnetwork-2/branches/master <!-- replace the URL -->
- [ ] Publish and notify #global-community
- [ ] Deploy and notify #instance-managers
- [ ] Nudge next release manager
The full process is described at https://github.com/openfoodfoundation/openfoodnetwork/wiki/Releasing.
[Draft new release]: https://github.com/openfoodfoundation/openfoodnetwork/releases/new?tag=v&title=v+Code+Name&body=Congrats%0A%0ADescription%0A%0A%23%23+User+facing+changes+:eyes:%0A%0A%0A%0A%23%23+Technical+changes+:wrench:%0A%0A

View File

@@ -39,11 +39,9 @@ Layout/LineLength:
- app/controllers/admin/variant_overrides_controller.rb
- app/controllers/api/enterprise_attachment_controller.rb
- app/controllers/api/product_images_controller.rb
- app/controllers/application_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/adjustments_controller_decorator.rb
- app/controllers/spree/admin/orders_controller_decorator.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/credit_cards_controller.rb
- app/controllers/spree/paypal_controller_decorator.rb
- app/controllers/stripe/callbacks_controller.rb
@@ -361,15 +359,15 @@ Metrics/AbcSize:
- app/controllers/enterprises_controller.rb
- app/controllers/spree/admin/adjustments_controller_decorator.rb
- app/controllers/spree/admin/image_settings_controller.rb
- app/controllers/spree/admin/orders/customer_details_controller_decorator.rb
- app/controllers/spree/admin/orders_controller_decorator.rb
- app/controllers/spree/admin/orders/customer_details_controller.rb
- app/controllers/spree/admin/orders_controller.rb
- app/controllers/spree/admin/overview_controller.rb
- app/controllers/spree/admin/payment_methods_controller.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/admin/payments_controller.rb
- app/controllers/spree/admin/products_controller.rb
- app/controllers/spree/admin/reports_controller.rb
- app/controllers/spree/admin/resource_controller.rb
- app/controllers/spree/admin/products_controller.rb
- app/controllers/spree/admin/search_controller_decorator.rb
- app/controllers/spree/admin/search_controller.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/admin/users_controller.rb
- app/controllers/spree/admin/variants_controller.rb
@@ -496,7 +494,6 @@ Metrics/CyclomaticComplexity:
- app/controllers/admin/enterprise_fees_controller.rb
- app/controllers/admin/enterprises_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/orders_controller.rb
- app/helpers/checkout_helper.rb
@@ -527,7 +524,6 @@ Metrics/PerceivedComplexity:
- app/controllers/admin/enterprises_controller.rb
- app/controllers/api/variants_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/orders_controller.rb
- app/helpers/checkout_helper.rb
@@ -567,13 +563,13 @@ Metrics/MethodLength:
- app/controllers/checkout_controller.rb
- app/controllers/shop_controller.rb
- app/controllers/spree/admin/image_settings_controller.rb
- app/controllers/spree/admin/orders/customer_details_controller_decorator.rb
- app/controllers/spree/admin/orders/customer_details_controller.rb
- app/controllers/spree/admin/orders_controller.rb
- app/controllers/spree/admin/payment_methods_controller.rb
- app/controllers/spree/admin/payments_controller_decorator.rb
- app/controllers/spree/admin/payments_controller.rb
- app/controllers/spree/admin/products_controller.rb
- app/controllers/spree/admin/reports_controller.rb
- app/controllers/spree/admin/resource_controller.rb
- app/controllers/spree/admin/products_controller.rb
- app/controllers/spree/admin/search_controller_decorator.rb
- app/controllers/spree/admin/tax_categories_controller.rb
- app/controllers/spree/admin/taxons_controller.rb
- app/controllers/spree/admin/users_controller.rb
@@ -652,8 +648,10 @@ Metrics/ClassLength:
- app/controllers/admin/order_cycles_controller.rb
- app/controllers/admin/subscriptions_controller.rb
- app/controllers/api/products_controller.rb
- app/controllers/application_controller.rb
- app/controllers/checkout_controller.rb
- app/controllers/spree/admin/base_controller.rb
- app/controllers/spree/admin/orders_controller.rb
- app/controllers/spree/admin/payment_methods_controller.rb
- app/controllers/spree/admin/reports_controller.rb
- app/controllers/spree/admin/resource_controller.rb

View File

@@ -335,6 +335,7 @@ Rails/OutputSafety:
- 'app/helpers/spree/admin/zones_helper.rb'
- 'app/helpers/spree/reports_helper.rb'
- 'app/helpers/spree/admin/navigation_helper.rb'
- 'app/helpers/spree/admin/orders_helper.rb'
- 'app/serializers/api/product_serializer.rb'
- 'lib/spree/money_decorator.rb'
- 'spec/features/admin/orders_spec.rb'

View File

@@ -166,7 +166,7 @@ GEM
bcrypt-ruby (3.1.5)
bcrypt (>= 3.1.3)
blockenspiel (0.5.0)
bugsnag (6.12.2)
bugsnag (6.13.0)
concurrent-ruby (~> 1.0)
builder (3.0.4)
byebug (9.0.6)
@@ -492,7 +492,7 @@ GEM
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
oj (3.10.1)
oj (3.10.2)
orm_adapter (0.5.0)
paper_trail (5.2.3)
activerecord (>= 3.0, < 6.0)
@@ -530,7 +530,7 @@ GEM
rack (1.4.7)
rack-cache (1.9.0)
rack (>= 0.4)
rack-mini-profiler (1.1.4)
rack-mini-profiler (1.1.6)
rack (>= 1.2.0)
rack-protection (1.5.5)
rack
@@ -620,7 +620,6 @@ GEM
rubocop-rails (2.4.2)
rack (>= 1.1)
rubocop (>= 0.72.0)
ruby-ole (1.2.12.1)
ruby-progressbar (1.10.1)
ruby-rc4 (0.1.5)
rubyzip (1.3.0)

View File

@@ -12,6 +12,10 @@
//= require jquery.ui.all
//= require jquery-ui-timepicker-addon
//= require jquery.powertip
//= require jquery.cookie
//= require jquery.jstree/jquery.jstree
//= require jquery.vAlign
//= require jquery.horizontalNav
//= require angular
//= require angular-resource
//= require angular-animate
@@ -23,8 +27,13 @@
//= require lodash.underscore.js
// spree
//= require spree
//= require admin/spree-select2
//= require admin/spree_backend
//= require modernizr
//= require spin
//= require jquery.adaptivemenu
//= require equalize
//= require css_browser_selector_dev
//= require responsive-tables
//= require admin/spree_paypal_express

View File

@@ -0,0 +1,228 @@
//= require_self
//= require admin/handlebar_extensions
//= require admin/variant_autocomplete
/**
This is a collection of javascript functions and whatnot
under the spree namespace that do stuff we find helpful.
Hopefully, this will evolve into a propper class.
**/
jQuery(function($) {
// Make main menu use full width
mainMenu = $('.fullwidth-menu')
if (typeof mainMenu.horizontalNav === 'function' )
mainMenu.horizontalNav({
tableDisplay: false,
responsiveDelay: 0
});
// Vertical align of checkbox fields
if (typeof $('.field.checkbox label').vAlign === 'function' )
$('.field.checkbox label').vAlign()
// if (typeof Spree !== 'undefined') {
// $('.main-menu-wrapper ul').AdaptiveMenu({
// text: "<a href='#'><i class='icon-chevron-down'></i> " + Spree.translations.more + "</a>",
// klass: "dropdown"
// });
// }
// Add some tips
if (typeof $('.with-tip').powerTip === 'function' ) {
$('.with-tip').powerTip({
smartPlacement: true,
fadeInTime: 50,
fadeOutTime: 50,
intentPollInterval: 300
});
$('.with-tip').on({
powerTipPreRender: function(){
$('#powerTip').addClass($(this).attr("data-action"));
$('#powerTip').addClass($(this).attr("data-tip-color"));
},
powerTipClose: function(){
$('#powerTip').removeClass($(this).attr("data-action"))
}
});
}
// Make flash messages dissapear
setTimeout('$(".flash").fadeOut()', 5000);
// Highlight hovered table column
$('table tbody tr td.actions a').hover(function(){
var tr = $(this).closest('tr');
var klass = 'highlight action-' + $(this).attr('data-action')
tr.addClass(klass)
tr.prev().addClass('before-' + klass);
}, function(){
var tr = $(this).closest('tr');
var klass = 'highlight action-' + $(this).attr('data-action')
tr.removeClass(klass)
tr.prev().removeClass('before-' + klass);
});
// Trunkate text in page_title that didn't fit
var truncate_elements = $('.truncate');
truncate_elements.each(function(){
$(this).trunk8();
});
$(window).resize(function (event) {
truncate_elements.each(function(){
$(this).trunk8();
})
});
// Make height of dt/dd elements the same
if (typeof $("dl").equalize === 'function' )
$("dl").equalize('outerHeight');
});
$.fn.visible = function(cond) { this[cond ? 'show' : 'hide' ]() };
// Overriding a broken function in Spree. Bug report at
// https://github.com/spree/spree/issues/4032
show_flash_error = function(message) {
error_div = $('.flash.error');
if (error_div.length > 0) {
error_div.html(message);
error_div.show();
} else {
if ($("#content .toolbar").length > 0) {
$("#content .toolbar").before('<div class="flash error">' + message + '</div>');
} else {
$("#progress").before('<div class="flash error">' + message + '</div>');
}
}
}
// Apply to individual radio button that makes another element visible when checked
$.fn.radioControlsVisibilityOfElement = function(dependentElementSelector){
if(!this.get(0)){ return }
showValue = this.get(0).value;
radioGroup = $("input[name='" + this.get(0).name + "']");
radioGroup.each(function(){
$(this).click(function(){
$(dependentElementSelector).visible(this.checked && this.value == showValue)
});
if(this.checked){ this.click() }
});
}
$(document).ready(function() {
if (typeof Spree !== 'undefined') {
handle_date_picker_fields = function(){
$('.datepicker').datepicker({
dateFormat: Spree.translations.date_picker,
dayNames: Spree.translations.abbr_day_names,
dayNamesMin: Spree.translations.abbr_day_names,
monthNames: Spree.translations.month_names,
prevText: Spree.translations.previous,
nextText: Spree.translations.next,
showOn: "focus"
});
// Correctly display range dates
$('.date-range-filter .datepicker-from').datepicker('option', 'onSelect', function(selectedDate) {
$(".date-range-filter .datepicker-to" ).datepicker( "option", "minDate", selectedDate );
});
$('.date-range-filter .datepicker-to').datepicker('option', 'onSelect', function(selectedDate) {
$(".date-range-filter .datepicker-from" ).datepicker( "option", "maxDate", selectedDate );
});
}
handle_date_picker_fields();
}
$(".observe_field").on('change', function() {
target = $(this).attr("data-update");
ajax_indicator = $(this).attr("data-ajax-indicator") || '#busy_indicator';
$(target).hide();
$(ajax_indicator).show();
$.ajax({ dataType: 'html',
url: $(this).attr("data-base-url")+encodeURIComponent($(this).val()),
type: 'get',
success: function(data){
$(target).html(data);
$(ajax_indicator).hide();
$(target).show();
}
});
});
$('.spree_add_fields').click(function() {
var target = $(this).data("target");
var new_table_row = $(target + ' tr:visible:last').clone();
var new_id = new Date().getTime();
new_table_row.find("input, select").each(function () {
var el = $(this);
el.val("");
if (typeof el.attr("id") !== 'undefined') el.attr("id", el.attr("id").replace(/\d+/, new_id))
if (typeof el.attr("name") !== 'undefined') el.attr("name", el.attr("name").replace(/\d+/, new_id))
})
// When cloning a new row, set the href of all icons to be an empty "#"
// This is so that clicking on them does not perform the actions for the
// duplicated row
new_table_row.find("a").each(function () {
var el = $(this);
el.attr('href', '#');
})
$(target).prepend(new_table_row);
})
// Fix sortable helper
var fixHelper = function(e, ui) {
ui.children().each(function() {
$(this).width($(this).width());
});
return ui;
};
$('table.sortable').ready(function(){
var td_count = $(this).find('tbody tr:first-child td').length
if (typeof $('table.sortable tbody').sortable !== 'function' )
return
$('table.sortable tbody').sortable(
{
handle: '.handle',
helper: fixHelper,
placeholder: 'ui-sortable-placeholder',
update: function(event, ui) {
$("#progress").show();
positions = {};
$.each($('table.sortable tbody tr'), function(position, obj){
reg = /spree_(\w+_?)+_(\d+)/;
parts = reg.exec($(obj).attr('id'));
if (parts) {
positions['positions['+parts[2]+']'] = position;
}
});
$.ajax({
type: 'POST',
dataType: 'script',
url: $(ui.item).closest("table.sortable").data("sortable-link"),
data: positions,
success: function(data){ $("#progress").hide(); }
});
},
start: function (event, ui) {
// Set correct height for placehoder (from dragged tr)
ui.placeholder.height(ui.item.height())
// Fix placeholder content to make it correct width
ui.placeholder.html("<td colspan='"+(td_count-1)+"'></td><td class='actions'></td>")
},
stop: function (event, ui) {
// Fix odd/even classes after reorder
$("table.sortable tr:even").removeClass("odd even").addClass("even");
$("table.sortable tr:odd").removeClass("odd even").addClass("odd");
}
});
});
});

View File

@@ -0,0 +1,27 @@
$(document).ready ->
opts =
lines: 11
length: 2
width: 3
radius: 9
corners: 1
rotate: 0
color: '#fff'
speed: 0.8
trail: 48
shadow: false
hwaccel: true
className: 'spinner'
zIndex: 2e9
top: 'auto'
left: 'auto'
target = document.getElementById("spinner")
$(document).ajaxStart ->
$("#progress").fadeIn()
spinner = new Spinner(opts).spin(target)
$(document).ajaxStop ->
$("#progress").fadeOut()

View File

@@ -0,0 +1,8 @@
//= require select2
jQuery(function($) {
// Make select beautiful
if (typeof $('select.select2').select2 === 'function' )
$('select.select2').select2({
allowClear: true
});
})

View File

@@ -0,0 +1,22 @@
root = exports ? this
root.taxon_tree_menu = (obj, context) ->
base_url = Spree.url(Spree.routes.taxonomy_taxons_path)
admin_base_url = Spree.url(Spree.routes.admin_taxonomy_taxons_path)
edit_url = admin_base_url.clone()
edit_url.setPath(edit_url.path() + '/' + obj.attr("id") + "/edit");
create:
label: "<i class='icon-plus'></i> " + Spree.translations.add,
action: (obj) -> context.create(obj)
rename:
label: "<i class='icon-pencil'></i> " + Spree.translations.rename,
action: (obj) -> context.rename(obj)
remove:
label: "<i class='icon-trash'></i> " + Spree.translations.remove,
action: (obj) -> context.remove(obj)
edit:
separator_before: true,
label: "<i class='icon-edit'></i> " + Spree.translations.edit,
action: (obj) -> window.location = edit_url.toString()

View File

@@ -0,0 +1,127 @@
handle_ajax_error = (XMLHttpRequest, textStatus, errorThrown) ->
$.jstree.rollback(last_rollback)
$("#ajax_error").show().html("<strong>" + server_error + "</strong><br />" + taxonomy_tree_error)
handle_move = (e, data) ->
last_rollback = data.rlbk
position = data.rslt.cp
node = data.rslt.o
new_parent = data.rslt.np
url = Spree.url(base_url).clone()
url.setPath url.path() + '/' + node.attr("id")
$.ajax
type: "POST",
dataType: "json",
url: url.toString(),
data: ({_method: "put", "taxon[parent_id]": new_parent.attr("id"), "taxon[position]": position }),
error: handle_ajax_error
true
handle_create = (e, data) ->
last_rollback = data.rlbk
node = data.rslt.obj
name = data.rslt.name
position = data.rslt.position
new_parent = data.rslt.parent
$.ajax
type: "POST",
dataType: "json",
url: base_url.toString(),
data: ({"taxon[name]": name, "taxon[parent_id]": new_parent.attr("id"), "taxon[position]": position }),
error: handle_ajax_error,
success: (data,result) ->
node.attr('id', data.id)
handle_rename = (e, data) ->
last_rollback = data.rlbk
node = data.rslt.obj
name = data.rslt.new_name
url = Spree.url(base_url).clone()
url.setPath(url.path() + '/' + node.attr("id"))
$.ajax
type: "POST",
dataType: "json",
url: url.toString(),
data: {_method: "put", "taxon[name]": name },
error: handle_ajax_error
handle_delete = (e, data) ->
last_rollback = data.rlbk
node = data.rslt.obj
delete_url = base_url.clone()
delete_url.setPath delete_url.path() + '/' + node.attr("id")
if confirm(Spree.translations.are_you_sure_delete)
$.ajax
type: "POST",
dataType: "json",
url: delete_url.toString(),
data: {_method: "delete"},
error: handle_ajax_error
else
$.jstree.rollback(last_rollback)
last_rollback = null
root = exports ? this
root.setup_taxonomy_tree = (taxonomy_id) ->
if taxonomy_id != undefined
# this is defined within admin/taxonomies/edit
root.base_url = Spree.url(Spree.routes.taxonomy_taxons_path)
$.ajax
url: base_url.path().replace("/taxons", "/jstree"),
success: (taxonomy) ->
last_rollback = null
conf =
json_data:
data: taxonomy,
ajax:
url: (e) ->
base_url.path() + '/' + e.attr('id') + '/jstree'
themes:
theme: "apple",
url: "/assets/jquery.jstree/themes/apple/style.css"
strings:
new_node: new_taxon,
loading: Spree.translations.loading + "..."
crrm:
move:
check_move: (m) ->
position = m.cp
node = m.o
new_parent = m.np
# no parent or cant drag and drop
if !new_parent || node.attr("rel") == "root"
return false
# can't drop before root
if new_parent.attr("id") == "taxonomy_tree" && position == 0
return false
true
contextmenu:
items: (obj) ->
taxon_tree_menu(obj, this)
plugins: ["themes", "json_data", "dnd", "crrm", "contextmenu"]
$("#taxonomy_tree").jstree(conf)
.bind("move_node.jstree", handle_move)
.bind("remove.jstree", handle_delete)
.bind("create.jstree", handle_create)
.bind("rename.jstree", handle_rename)
.bind "loaded.jstree", ->
$(this).jstree("core").toggle_node($('.jstree-icon').first())
$("#taxonomy_tree a").on "dblclick", (e) ->
$("#taxonomy_tree").jstree("rename", this)
# surpress form submit on enter/return
$(document).keypress (e) ->
if e.keyCode == 13
e.preventDefault()

View File

@@ -16,22 +16,6 @@ $(document).ready(function() {
});
});
// Overriding a broken function in Spree. Bug report at
// https://github.com/spree/spree/issues/4032
show_flash_error = function(message) {
error_div = $('.flash.error');
if (error_div.length > 0) {
error_div.html(message);
error_div.show();
} else {
if ($("#content .toolbar").length > 0) {
$("#content .toolbar").before('<div class="flash error">' + message + '</div>');
} else {
$("#progress").before('<div class="flash error">' + message + '</div>');
}
}
}
$(document).ready(function(){
$('a.close').click(function(event){
event.preventDefault();

View File

@@ -7,6 +7,9 @@
*= require admin/spree_backend
*= require jquery.powertip
*= require responsive-tables
*= require normalize
*= require skeleton
*= require jquery.ui.datepicker
*= require jquery-ui-timepicker-addon
*= require shared/textAngular
*= require shared/ng-tags-input.min
@@ -14,15 +17,27 @@
*= require_self
*/
//************************************************************************//
//************************************************************************//
@import 'globals/functions';
@import 'globals/variables';
@import 'variables';
@import 'globals/mixins';
@import 'shared/typography';
@import 'shared/tables';
@import 'shared/icons';
@import 'shared/forms';
@import 'shared/layout';
@import 'plugins/powertip';
@import 'plugins/jstree';
@import 'plugins/font-awesome';
@import 'hacks/mozilla';
@import 'hacks/opera';
@import 'hacks/ie';
@import 'variables';
@import 'components/*';
@import 'plugins/font-awesome';
@import 'pages/*';
@import '*';

View File

@@ -0,0 +1,33 @@
@import 'admin/globals/variables';
table tbody tr {
&.highlight {
@each $action in $actions {
&.action-#{$action} td {
background-color: get-value($actions, $actions-bg-colors, $action);
border-color: get-value($actions, $actions-brd-colors, $action);
}
}
&.action-remove td, &.action-void td {
text-decoration: line-through;
&.actions {
text-decoration: none;
}
}
}
&.before-highlight {
@each $action in $actions {
&.action-#{$action} td {
border-bottom-color: get-value($actions, $actions-brd-colors, $action);
}
}
}
td.actions {
background-color: transparent !important;
}
}

View File

@@ -1,12 +0,0 @@
#admin-menu {
li {
a {
font-weight: 600;
}
a::before {
font-weight: normal;
padding-top: 0;
}
}
}

View File

@@ -0,0 +1,158 @@
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
@import 'admin/plugins/font-awesome';
.date-range-filter {
.range-divider {
padding: 0;
}
input.datepicker {
width: 96px !important;
}
}
#ui-datepicker-div {
@include border-radius($border-radius);
border-color: $color-3;
padding: 0;
margin-top: 10px;
&:before {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid $color-3;
top: 0px;
margin-top: -10px;
left: 25px;
z-index: 1;
}
.ui-datepicker-header {
padding: 0;
background-image: none;
background-color: $color-3;
border: none;
border-bottom: none;
border-radius: 0;
height: 32px;
.ui-datepicker-prev, .ui-datepicker-next {
border-radius: 0;
top: 0;
height: 32px;
&:hover {
border: none;
background-image: none;
background-color: $color-3;
cursor: pointer;
}
.ui-icon {
background-image: none;
text-indent: 0;
color: $color-1;
width: 10px;
margin-left: -5px;
@extend [class^="icon-"]:before;
&:hover {
color: very-light($color-2, 25);
}
}
}
.ui-datepicker-prev {
left: 0;
.ui-icon {
@extend .icon-arrow-left;
}
}
.ui-datepicker-next {
right: 0;
.ui-icon {
@extend .icon-arrow-right;
}
&:hover {
.ui-icon {
margin-left: -5px;
}
}
}
.ui-datepicker-title {
color: $color-1;
text-transform: uppercase;
font-size: 85% !important;
padding: 6px 10px;
}
}
table.ui-datepicker-calendar {
border: none;
thead {
th {
border-bottom: 1px solid $color-border;
border-right: 1px solid $color-border;
color: $color-body-text;
width: 33px;
&:last-child {
border-right: none;
}
}
}
tbody {
tr:hover {
td {
background-color: transparent !important;
}
}
&:last-child tr:last-child td {
border-bottom: none;
}
td {
a {
border: 1px solid transparent;
background-color: $color-1;
background-image: none;
font-size: 85%;
color: $color-body-text;
&.ui-state-active {
background-color: $color-2;
color: $color-1;
}
&:hover {
background-color: $color-2;
color: $color-1;
border-color: darken($color-2, 5);
}
}
&.ui-state-disabled {
.ui-state-default {
border: none;
background-image: none;
background-color: transparent;
}
}
&.ui-datepicker-today {
a {
background-color: $color-6;
color: $color-1;
border: 1px solid darken($color-6, 5);
}
}
}
}
}
}

View File

@@ -0,0 +1,45 @@
@import 'admin/globals/variables';
.errorExplanation {
padding: 5px;
border: 1px solid very-light($color-error, 12);
background-color: very-light($color-error, 6);
border-radius: 3px;
color: very-light($color-error, 30);
margin-bottom: 15px;
h2 {
font-size: 140%;
color: very-light($color-error, 30);
margin-bottom: 5px;
}
p {
padding: 10px 0;
}
ul {
list-style-position: inside;
li {
font-weight: $font-weight-bold;
}
}
}
.flash {
position: fixed;
top: 0;
left: 0;
width: 100%;
padding: 16px;
text-align: center;
z-index: 1000;
font-size: 120%;
color: $color-1;
font-weight: 600;
&.notice { background-color: rgba($color-notice, 0.8) }
&.success { background-color: rgba($color-success, 0.8) }
&.error { background-color: rgba($color-error, 0.8) }
}

View File

@@ -0,0 +1,162 @@
@import 'admin/globals/variables';
// Navigation
//---------------------------------------------------
.inline-menu {
margin: 0;
-webkit-margin-before: 0;
-webkit-padding-start: 0;
}
nav.menu {
ul {
list-style: none;
li {
a {
padding: 10px 0;
display: block;
position: relative;
text-align: left;
border: 1px solid transparent;
text-transform: uppercase;
font-weight: 600;
font-size: 90%;
}
&.active a {
color: $color-2;
border-left-width: 0;
border-bottom-color: $color-2;
}
&:hover a {
color: $color-2;
}
}
}
}
[data-hook="admin_login_navigation_bar"] {
ul {
text-align: right;
li {
padding: 5px 0 5px 10px;
text-align: right;
font-size: 90%;
color: $color-link;
margin-top: 8px;
&[data-hook="user-logged-in-as"] {
width: 50%;
color: $color-body-text;
}
&:hover {
i {
color: $color-2;
}
}
}
}
}
#admin-menu {
background-color: $color-3;
li {
min-width: 90px;
a {
display: block;
padding: 25px 20px;
color: $color-1 !important;
text-transform: uppercase;
position: relative;
text-align: center;
font-weight: 600;
i {
display: inline;
}
&:hover {
background-color: $color-2;
&:after {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 5px solid $color-2;
bottom: 0px;
margin-bottom: -5px;
left: 50%;
margin-left: -10px;
z-index: 1;
}
}
span.text {
font-weight: 600;
}
}
a::before {
font-weight: normal;
padding-top: 0;
}
.dropdown {
width: 300px;
background-color: $color-3;
width: 200px;
z-index: 100000;
> li {
width: 200px !important;
a:after {
display: none;
}
}
}
&.selected a {
@extend a:hover;
}
}
}
#sub-menu {
background-color: $color-2;
padding-bottom: 0;
li {
a {
display: block;
padding: 12px 20px;
color: $color-1;
text-align: center;
text-transform: uppercase;
position: relative;
font-size: 85%;
}
&.selected a, a:hover {
&:after {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 5px solid $color-2;
bottom: 0px;
margin-bottom: -5px;
left: 50%;
margin-left: -10px;
z-index: 1;
}
}
}
}

View File

@@ -1,8 +1,23 @@
@import 'admin/globals/variables';
@import "admin/variables";
.pagination {
text-align: center;
margin: 2em 0 1em;
padding: 10px 0;
.page {
padding: 5px 8px;
text-align: center;
display: inline-block;
text-align: center;
&.current {
background-color: $color-2;
border-radius: 3px;
color: $color-1;
}
}
button {
margin: 0 0.35em;

View File

@@ -0,0 +1,38 @@
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
#progress {
display: none;
position: fixed;
top: 0;
z-index: 1000;
opacity: 0.8;
width: 100%;
.wrapper {
@include border-radius(10px);
top: -10px;
position: absolute;
left: 50%;
width: 200px;
margin-left: -100px;
padding: 11px 0;
background-color: $color-3;
color: $color-1;
text-align: center;
}
#spinner {
position: absolute;
top: 10px;
left: 50%;
margin-left: -5px;
}
.progress-message {
font-size: 120%;
font-weight: $font-weight-bold;
margin-top: 20px;
text-transform: uppercase;
}
}

View File

@@ -0,0 +1,28 @@
@import 'admin/globals/variables';
// Sidebar
//---------------------------------------------------
#sidebar {
overflow: visible;
border-top: 1px solid $color-border;
margin-top: 17px;
.sidebar-title {
color: $color-2;
text-transform: uppercase;
text-align: center;
font-size: 14px;
font-weight: 600;
> span {
display: inline;
background: #fff;
padding: 5px 10px;
position: relative;
top: -14px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
}

View File

@@ -0,0 +1,36 @@
@import 'admin/globals/variables';
.state {
text-transform: uppercase;
font-size: 80%;
font-weight: 600;
&:before {
content: '';
position: relative;
display: inline-block;
margin-right: 3px;
border-radius: $body-font-size/2;
width: $body-font-size - 4px;
height: $body-font-size - 4px;
}
@each $state in $states {
&.#{$state}:before {
background-color: get-value($states, $states-bg-colors, $state);
// &, a {
// color: get-value($states, $states-text-colors, $state);
// }
}
}
}
table tbody tr {
&[class*="state"] td:first-child {
border-left-width: 3px;
}
&.state-complete td:first-child { border-left-color: $color-success }
&.state-cart td:first-child { border-left-color: very-light($color-notice, 6) }
&.state-canceled td:first-child { border-left-color: $color-error }
}

View File

@@ -0,0 +1,14 @@
#table-filter {
.field {
input[type="text"], input[type="phone"],
input[type="email"], input[type="number"],
input[type="url"] {
width: 100%;
}
}
.actions {
text-align: center;
}
}

View File

@@ -0,0 +1,25 @@
// Make color very close to white
@function very-light($color, $adjust: 3){
@if type-of($adjust) == 'number' and $adjust > 0 {
@for $i from 0 through 100 {
@if lighten($color, $i) == white and ($i - $adjust) > $adjust {
@return lighten($color, $i - $adjust);
}
}
}
@else {
@debug "Please correct $adjust value. It should be number and larger then 0. Currently it is '#{type-of($adjust)}' with value '#{$adjust}'"
}
};
// Quick fix for dynamic variables missing in SASS
@function get-value($prop, $val, $search) {
$n1: index($prop, $search);
$n2: index($val, $search);
@if($n1) {
@return nth($val, $n1);
} @else {
@return nth($prop, $n2);
}
}

View File

@@ -0,0 +1,135 @@
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
@import 'admin/plugins/font-awesome';
#taxonomy_tree {
> ul, .jstree-icon {
background-image: none;
}
.jstree-icon {
@extend [class^="icon-"]:before;
}
.jstree-open > .jstree-icon {
@extend .icon-caret-down;
}
.jstree-closed > .jstree-icon {
@extend .icon-caret-right;
}
li {
background-image: none;
a {
background-color: very-light($color-3);
border: 1px solid $color-border;
color: $color-body-text;
font-weight: $font-weight-bold;
text-shadow: none;
width: 90%;
height: auto;
line-height: inherit;
padding: 5px 0 5px 10px;
margin-bottom: 10px;
.jstree-icon {
padding-left: 0px;
@extend .icon-move;
}
}
}
}
#vakata-dragged.jstree-apple .jstree-invalid,
#vakata-dragged.jstree-apple .jstree-ok,
#jstree-marker {
background-image: none !important;
background-color: transparent !important;
@extend [class^="icon-"]:before;
}
#vakata-dragged.jstree-apple .jstree-invalid {
@extend .icon-remove;
color: $color-5;
}
#vakata-dragged.jstree-apple .jstree-ok {
@extend .icon-ok;
color: $color-2;
}
#jstree-marker {
@extend .icon-caret-right;
color: $color-body-text !important;
width: 4px !important;
}
#jstree-marker-line {
@include border-radius($border-radius !important);
height: 0px !important;
margin-left: 5px !important;
margin-top: -2px !important;
border: none !important;
border-bottom: 1px solid $color-body-text !important;
background-color: very-light($color-3) !important;
-webkit-box-shadow: none !important;
-moz-box-shadow: none !important;
box-shadow: none !important;
}
#vakata-contextmenu {
background-color: $color-3 !important;
-moz-box-shadow: none !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
border: none !important;
@include border-radius($border-radius !important);
&:before {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid $color-3;
top: 0px;
margin-top: -10px;
left: 25px;
z-index: 1;
}
a {
color: $color-1 !important;
line-height: inherit !important;
padding: 5px 10px !important;
margin: 0 !important;
font-size: 90% !important;
&:hover {
@include border-radius($border-radius !important);
background-color: $color-2 !important;
border: none !important;
-moz-box-shadow: none !important;
-webkit-box-shadow: none !important;
line-height: inherit !important;
padding: 5px 10px !important;
margin: 0 !important;
}
}
li:first-child a:hover:before {
content: '';
position: absolute;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid $color-2;
top: 0px;
margin-top: -10px;
left: 25px;
z-index: 1;
}
li.vakata-separator {
display: none;
}
}

View File

@@ -0,0 +1,193 @@
@import 'admin/globals/functions';
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
@import 'admin/shared/forms';
@import 'admin/plugins/font-awesome';
.select2-container {
&:hover .select2-choice, &.select2-container-active .select2-choice {
background-color: $color-sel-hover-bg !important;
border-color: $color-sel-hover-bg !important;
}
.select2-choice {
background-image: none !important;
background-color: $color-sel-bg;
border: none !important;
box-shadow: none !important;
@include border-radius($border-radius);
color: $color-1 !important;
font-size: 90%;
height: 31px;
line-height: inherit !important;
padding: 5px 15px 7px;
span {
display: block;
padding: 2px;
}
.select2-search-choice-close {
background-image: none !important;
font-size: 100% !important;
@extend .icon-remove;
@extend [class^="icon-"]:before;
margin-top: 2px;
}
}
&.select2-container-active {
.select2-choice {
box-shadow: none !important;
}
&.select2-dropdown-open .select2-choice div b {
@extend .icon-caret-up
}
}
}
.select2-drop {
border-color: $color-sel-hover-bg;
box-shadow: none !important;
z-index: 1000000;
&.select2-drop-above {
border-color: $color-sel-hover-bg;
}
}
.select2-search {
@extend .icon-search;
font-size: 100%;
color: darken($color-border, 15);
padding: 0 9px 0 0;
&:before {
@extend [class^="icon-"]:before;
position: absolute;
top: 13px;
left: 13px;
}
input {
@extend input[type="text"];
padding: 6px 0 6px 25px;
margin: 5px 0 0 5px;
font-family: $base-font-family;
font-size: 90%;
box-shadow: none;
background-image: none;
}
}
.select2-container .select2-choice .select2-arrow {
background-image: none;
background: transparent;
border: 0;
b {
padding-top: 7px;
display: block;
width: 100%;
height: 100%;
background: none;
font-family: FontAwesome;
font-weight: 200 !important;
&:before {
content: "\f0d7";
}
}
}
.select2-results {
padding-left: 0 !important;
li {
font-size: 85% !important;
&.select2-highlighted {
.select2-result-label {
&, h6 {
color: $color-1 !important;
}
}
}
.select2-result-label {
color: $color-body-text;
min-height: 22px;
clear: both;
overflow: auto;
}
&.select2-no-results, &.select2-searching {
padding: 5px;
background-color: transparent;
color: $color-body-text;
text-align: center;
font-weight: $font-weight-bold;
text-transform: uppercase;
}
}
.select2-highlighted {
background-color: $color-sel-bg;
}
}
.select2-container-multi {
&.select2-container-active, &.select2-dropdown-open {
.select2-choices {
border-color: $color-sel-hover-bg !important;
box-shadow: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
.select2-choices {
@extend input[type="text"];
padding: 6px 3px 3px 3px;
box-shadow: none;
background-image: none !important;
.select2-search-choice {
@include border-radius($border-radius);
margin: 0 0 3px 3px;
background-image: none;
background-color: $color-sel-bg;
border: none;
box-shadow: none;
color: $color-1 !important;
font-size: 85%;
&:hover {
background-color: $color-sel-hover-bg;
}
.select2-search-choice-close {
background-image: none !important;
font-size: 85% !important;
@extend .icon-remove;
@extend [class^="icon-"]:before;
margin-left: 2px;
color: $color-1;
}
}
}
}
label .select2-container {
margin-top: -6px;
.select2-choice {
span {
text-transform: none;
font-weight: normal;
}
}
}

View File

@@ -0,0 +1,270 @@
@import 'admin/globals/variables';
@import 'admin/globals/mixins';
input[type="text"],
input[type="password"],
input[type="email"],
input[type="date"],
input[type="datetime"],
input[type="time"],
input[type="url"],
input[type="number"],
input[type="tel"],
textarea, fieldset {
@include border-radius($border-radius);
padding: 7px 10px;
border: 1px solid $color-txt-brd;
color: $color-txt-text;
font-size: 90%;
&:focus {
outline: none;
border-color: $color-txt-hover-brd;
}
&[disabled] {
opacity: 0.7;
}
}
textarea {
line-height: 19px;
}
.fullwidth {
width: 100%;
}
label {
font-weight: 600;
text-transform: uppercase;
font-size: 85%;
display: inline;
margin-bottom: 5px;
color: $color-4;
&.inline {
display: inline-block !important;
}
&.block {
display: block !important;
}
}
.label-block label { display: block }
input[type="submit"],
input[type="button"],
button, .button {
@include border-radius($border-radius);
display: inline-block;
padding: 8px 15px;
border: none;
background-color: $color-btn-bg;
color: $color-btn-text;
text-transform: uppercase;
font-weight: 600 !important;
&:before {
font-weight: normal !important;
}
&:visited, &:active, &:focus { color: $color-btn-text }
&:hover {
background-color: $color-btn-hover-bg;
color: $color-btn-hover-text;
}
&:active:focus {
box-shadow: 0 0 8px 0 darken($color-btn-hover-bg, 5) inset;
}
&.fullwidth {
width: 100%;
text-align: center;
}
}
span.info {
font-style: italic;
font-size: 85%;
color: lighten($color-body-text, 15);
display: block;
line-height: 20px;
margin: 5px 0;
}
.field {
padding: 10px 0;
&.checkbox {
min-height: 73px;
input[type="checkbox"] {
display: inline-block;
width: auto;
}
label {
cursor: pointer;
display: block;
}
}
ul {
border-top: 1px solid $color-border;
list-style: none;
padding-top: 5px;
li {
display: inline-block;
padding-right: 10px;
label {
font-weight: normal;
text-transform: none;
}
&.white-space-nowrap {
white-space: nowrap;
}
}
}
&.withError {
.field_with_errors {
label {
color: very-light($color-error, 30);
}
input {
border-color: very-light($color-error, 15);
}
}
.formError {
color: very-light($color-error, 30);
font-style: italic;
font-size: 85%;
}
}
}
fieldset {
box-shadow: none;
box-sizing: border-box;
border-color: $color-border;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
margin-left: 0;
margin-right: 0;
position: relative;
margin-bottom: 35px;
padding: 10px 0 15px 0;
background-color: transparent;
border-left: none;
border-right: none;
border-radius: 0;
&.no-border-bottom {
border-bottom: none;
margin-bottom: 0;
}
&.no-border-top {
border-top: none;
padding-top: 0;
}
legend {
background-color: $color-1;
color: $color-2;
font-size: 14px;
font-weight: 600;
text-transform: uppercase;
text-align: center;
padding: 8px 15px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
i {
color: $color-link;
}
}
label {
color: lighten($color-body-text, 8);
}
.filter-actions {
margin-bottom: -32px;
margin-top: 15px;
text-align: center;
form {
display: inline-block;
}
button, .button, input[type="submit"], input[type="button"], span.or {
@include border-radius($border-radius);
-webkit-box-shadow: 0 0 0 15px $color-1;
-moz-box-shadow: 0 0 0 15px $color-1;
-ms-box-shadow: 0 0 0 15px $color-1;
-o-box-shadow: 0 0 0 15px $color-1;
box-shadow: 0 0 0 15px $color-1;
&:hover {
border-color: $color-1;
}
}
span.or {
background-color: $color-1;
border-width: 5px;
margin-left: 5px;
margin-right: 5px;
position: relative;
-webkit-box-shadow: 0 0 0 5px $color-1;
-moz-box-shadow: 0 0 0 5px $color-1;
-ms-box-shadow: 0 0 0 5px $color-1;
-o-box-shadow: 0 0 0 5px $color-1;
box-shadow: 0 0 0 5px $color-1;
}
}
&.labels-inline {
.field {
margin-bottom: 0;
display: table;
width: 100%;
label, input {
display: table-cell !important;
}
input {
width: 100%;
}
&.checkbox {
input {
width: auto !important
}
}
}
.actions {
padding: 0;
text-align: right;
}
}
}
.form-actions {
margin-top: 18px;
}
.form-buttons {
text-align: center;
}

View File

@@ -0,0 +1,25 @@
@import 'admin/plugins/font-awesome';
// Some fixes for fontwesome stylesheets
[class^="icon-"], [class*=" icon-"] {
&:before {
padding-right: 5px;
}
&.button, &.icon_link {
width: auto;
&:before {
padding-top: 3px;
}
}
}
.icon-email:before { @extend .icon-envelope:before }
.icon-resume:before { @extend .icon-refresh:before }
.icon-cancel:before,
.icon-void:before { @extend .icon-remove:before }
.icon-capture:before { @extend .icon-ok:before }
.icon-credit:before { @extend .icon-ok:before }

View File

@@ -0,0 +1,92 @@
@import 'admin/globals/variables';
// Basics
//---------------------------------------------------
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
// Helpers
.block-table {
display: table;
width: 100%;
.table-cell {
display: table-cell;
vertical-align: middle;
padding: 0 10px;
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
}
}
}
.hidden {
display: none;
}
// For block grids
.frameless {
margin-left: -10px;
margin-right: -10px;
}
// Header
//---------------------------------------------------
#header {
background-color: $color-1;
padding: 5px 0;
}
#logo { height: 40px }
[data-hook="admin-title"] { font-size: 14px }
.page-title {
i {
color: $color-2;
}
}
// Content
//---------------------------------------------------
#content {
background-color: $color-1;
position: relative;
z-index: 0;
padding: 0;
margin-top: 15px;
}
#content-header {
padding: 15px 0;
background-color: very-light($color-3, 4);
border-bottom: 1px solid $color-border;
.page-title {
font-size: 20px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.page-actions {
text-align: right;
form {
display: inline-block;
}
}
}
// Footer
//---------------------------------------------------
#footer {
margin-top: 15px;
border-top: 1px solid $color-border;
padding: 10px 0;
}

View File

@@ -0,0 +1,208 @@
@import 'admin/globals/variables';
@import 'admin/plugins/font-awesome';
table {
width: 100%;
margin-bottom: 15px;
border-collapse: separate;
th, td {
padding: 7px 5px;
border-right: 1px solid $color-border;
border-bottom: 1px solid $color-border;
vertical-align: middle;
text-overflow: ellipsis;
img {
border: 1px solid transparent;
}
&:first-child {
border-left: 1px solid $color-border;
}
a {
border-bottom: 1px dotted lighten($color-link, 10);
&:hover {
border-color: lighten($color-link-hover, 10);
}
}
.handle {
display: block !important;
text-align: center;
padding-right: 0;
}
&.actions {
background-color: transparent;
border: none !important;
text-align: center;
span.text {
font-size: $body-font-size;
}
[class*='icon-'].no-text {
font-size: 120%;
background-color: very-light($color-3);
border: 1px solid $color-border;
border-radius: 15px;
width: 29px;
height: 29px;
display: inline-block;
padding-top: 2px;
&:before {
text-align: center !important;
width: 27px;
display: inline-block;
}
&:hover {
border-color: transparent;
}
}
button[class*='icon-'] {
color: $color-link;
padding: 0 !important;
}
.icon-envelope-alt, .icon-eye-open {
color: $color-link;
padding-left: 0px;
&:hover {
background-color: $color-3;
color: $color-1;
}
}
.icon-trash:hover, .icon-void:hover {
background-color: $color-error;
color: $color-1;
}
.icon-cancel:hover {
background-color: $color-notice;
color: $color-1;
}
.icon-edit:hover, .icon-capture:hover, .icon-ok:hover, .icon-plus:hover {
background-color: $color-success;
color: $color-1;
}
.icon-copy:hover {
background-color: $color-notice;
color: $color-1;
}
}
input[type="number"],
input[type="text"] {
width: 100%;
}
&.no-border {
border-right: none;
}
.handle {
@extend [class^="icon-"]:before;
@extend .icon-reorder;
cursor: move;
}
}
&.no-borders {
td, th {
border: none !important;
}
}
thead {
th {
padding: 10px;
border-top: 1px solid $color-border;
border-bottom: none;
background-color: $color-tbl-thead;
text-transform: uppercase;
font-size: 85%;
font-weight: $font-weight-bold;
}
}
tbody {
tr {
&:first-child th,
&:first-child td {
border-top: 1px solid $color-border;
}
&.even td {
background-color: $color-tbl-even;
img {
border: 1px solid very-light($color-3, 6);
}
}
&:hover td {
background-color: very-light($color-3, 5);
img {
border: 1px solid $color-border;
}
}
&.deleted td {
background-color: very-light($color-error, 6);
border-color: very-light($color-error, 15);
}
&.ui-sortable-placeholder td {
border: 1px solid $color-2 !important;
visibility: visible !important;
&.actions {
background-color: transparent;
border-right: none !important;
border-top: none !important;
border-bottom: none !important;
border-left: 1px solid $color-2 !important;
}
}
&.ui-sortable-helper {
width: 100%;
td {
background-color: lighten($color-3, 33);
border-bottom: 1px solid $color-border;
&.actions {
display: none;
}
}
}
}
&.no-border-top tr:first-child td {
border-top: none;
}
&.grand-total {
td {
border-color: $color-2 !important;
text-transform: uppercase;
font-size: 110%;
font-weight: 600;
background-color: lighten($color-2, 50);
}
.total {
background-color: $color-2;
color: $color-1;
}
}
}
}

View File

@@ -0,0 +1,134 @@
@import 'admin/globals/variables';
// Base
//--------------------------------------------------------------
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; font-size: 13px; }
body {
font-family: $base-font-family;
font-size: $body-font-size;
font-weight: 400;
color: $color-body-text;
text-rendering: optimizeLegibility;
}
hr {
border-top: 1px solid $color-border;
border-bottom: 1px solid white;
border-left: none;
}
strong, b {
font-weight: 600;
}
// links
//--------------------------------------------------------------
a {
color: $color-link;
text-decoration: none;
line-height: inherit;
&, &:hover, &:active, &:visited, &:focus {
outline: none;
}
&:visited {
color: $color-link-visited;
}
&:focus {
color: $color-link-focus;
}
&:active {
color: $color-link-active;
}
&:hover {
color: $color-link-hover;
}
}
// Headings
//--------------------------------------------------------------
h1,h2,h3,h4,h5,h6 {
font-weight: 600;
color: $color-headers;
line-height: 1.1;
}
h1 { font-size: $h1-size; line-height: $h1-size + 6 }
h2 { font-size: $h2-size; line-height: $h1-size + 4 }
h3 { font-size: $h3-size; line-height: $h1-size + 2 }
h4 { font-size: $h4-size; line-height: $h1-size }
h5 { font-size: $h5-size; line-height: $h1-size }
h6 { font-size: $h6-size; line-height: $h1-size }
// Lists
//--------------------------------------------------------------
ul {
&.inline-menu {
li {
display: inline-block;
}
}
&.fields {
list-style: none;
padding: 0;
margin: 0;
}
}
dl {
width: 100%;
overflow: hidden;
margin: 5px 0;
color: lighten($color-body-text, 15);
dt, dd {
float: left;
line-height: 16px;
padding: 5px;
text-align: justify;
}
dt {
width: 40%;
font-weight: 600;
padding-left: 0;
text-transform: uppercase;
font-size: 85%;
}
dd {
width: 60%;
padding-right: 0;
}
dd:after {
content: '';
clear: both;
}
}
// Helpers
.align-center { text-align: center }
.align-right { text-align: right }
.align-left { text-align: left }
.align-justify { text-align: justify }
.uppercase { text-transform: uppercase }
.green { color: $color-2 }
.blue { color: $color-3 }
.red { color: $color-5 }
.yellow { color: $color-6 }
.no-objects-found {
text-align: center;
font-size: 120%;
text-transform: uppercase;
padding: 40px 0px;
color: lighten($color-body-text, 15);
}

View File

@@ -23,7 +23,11 @@ class ApplicationController < ActionController::Base
referer_path = OpenFoodNetwork::RefererParser.path(request.referer)
if referer_path
is_checkout_path_the_referer = [main_app.checkout_path].include?(referer_path)
session["spree_user_return_to"] = is_checkout_path_the_referer ? referer_path : root_path
session["spree_user_return_to"] = if is_checkout_path_the_referer
referer_path
else
main_app.root_path
end
end
end
@@ -48,11 +52,11 @@ class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource_or_scope)
return session[:shopfront_redirect] if session[:shopfront_redirect]
stored_location_for(resource_or_scope) || signed_in_root_path(resource_or_scope)
stored_location_for(resource_or_scope) || main_app.root_path
end
def after_sign_out_path_for(_resource_or_scope)
session[:shopfront_redirect] || root_path
session[:shopfront_redirect] || main_app.root_path
end
private
@@ -74,7 +78,7 @@ class ApplicationController < ActionController::Base
def require_distributor_chosen
unless @distributor = current_distributor
redirect_to spree.root_path
redirect_to main_app.root_path
false
end
end
@@ -86,26 +90,29 @@ class ApplicationController < ActionController::Base
end
def check_hub_ready_for_checkout
# This condition is more rigourous than required by development to avoid coupling this
# condition to every controller spec
if current_distributor && current_order &&
current_distributor.respond_to?(:ready_for_checkout?) &&
!current_distributor.ready_for_checkout?
if current_distributor_closed?
current_order.empty!
current_order.set_distribution! nil, nil
flash[:info] = "The hub you have selected is temporarily closed for orders. Please try again later."
redirect_to root_url
flash[:info] = "The hub you have selected is temporarily closed for orders. "\
"Please try again later."
redirect_to main_app.root_url
end
end
def current_distributor_closed?
current_distributor &&
current_order &&
current_distributor.respond_to?(:ready_for_checkout?) &&
!current_distributor.ready_for_checkout?
end
def check_order_cycle_expiry
if current_order_cycle.andand.closed?
session[:expired_order_cycle_id] = current_order_cycle.id
current_order.empty!
current_order.set_order_cycle! nil
flash[:info] = "The order cycle you've selected has just closed. Please try again!"
redirect_to root_url
redirect_to main_app.root_url
end
end

View File

@@ -15,11 +15,10 @@ module Spree
# Warn the user when they have an active order cycle with hubs that are not ready
# for checkout (ie. does not have valid shipping and payment methods).
def warn_invalid_order_cycles
distributors = active_distributors_not_ready_for_checkout
return if flash[:notice].present?
return if distributors.empty? || flash[:notice].present?
flash[:notice] = active_distributors_not_ready_for_checkout_message(distributors)
warning = OrderCycleWarning.new(spree_current_user).call
flash[:notice] = warning if warning.present?
end
# This is in Spree::Core::ControllerHelpers::Auth
@@ -30,7 +29,7 @@ module Spree
redirect_to '/unauthorized'
else
store_location
redirect_to root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}")
redirect_to main_app.root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}")
end
end
@@ -93,24 +92,6 @@ module Spree
private
def active_distributors_not_ready_for_checkout
ocs = OrderCycle.managed_by(spree_current_user).active
distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq
Enterprise.where('enterprises.id IN (?)', distributors).not_ready_for_checkout
end
def active_distributors_not_ready_for_checkout_message(distributors)
distributor_names = distributors.map(&:name).join ', '
if distributors.count > 1
I18n.t(:active_distributors_not_ready_for_checkout_message_plural,
distributor_names: distributor_names)
else
I18n.t(:active_distributors_not_ready_for_checkout_message_singular,
distributor_names: distributor_names)
end
end
def html_request?
request.format.html?
end
@@ -121,13 +102,17 @@ module Spree
def render_as_json(data, options = {})
ams_prefix = options.delete :ams_prefix
if [Array, ActiveRecord::Relation].include? data.class
if each_serializer_required?(data)
render options.merge(json: data, each_serializer: serializer(ams_prefix))
else
render options.merge(json: data, serializer: serializer(ams_prefix))
end
end
def each_serializer_required?(data)
['Array', 'ActiveRecord::Relation'].include?(data.class.name)
end
def serializer(ams_prefix)
unless ams_prefix.nil? || ams_prefix_whitelist.include?(ams_prefix.to_sym)
raise "Suffix '#{ams_prefix}' not found in ams_prefix_whitelist for #{self.class.name}."

View File

@@ -0,0 +1,71 @@
module Spree
module Admin
module Orders
class CustomerDetailsController < Spree::Admin::BaseController
before_filter :load_order
before_filter :check_authorization
before_filter :set_guest_checkout_status, only: :update
def show
edit
render action: :edit
end
def edit
country_id = Address.default.country.id
@order.build_bill_address(country_id: country_id) if @order.bill_address.nil?
@order.build_ship_address(country_id: country_id) if @order.ship_address.nil?
end
def update
if @order.update_attributes(params[:order])
if params[:guest_checkout] == "false"
@order.associate_user!(Spree.user_class.find_by_email(@order.email))
end
AdvanceOrderService.new(@order).call
@order.shipments.map(&:refresh_rates)
flash[:success] = Spree.t('customer_details_updated')
redirect_to admin_order_customer_path(@order)
else
render action: :edit
end
end
# Inherit CanCan permissions for the current order
def model_class
load_order unless @order
@order
end
private
def load_order
@order = Order.find_by_number!(params[:order_id], include: :adjustments)
end
def check_authorization
load_order
session[:access_token] ||= params[:token]
resource = @order
action = params[:action].to_sym
action = :edit if action == :show # show route renders :edit for this controller
authorize! action, resource, session[:access_token]
end
def set_guest_checkout_status
registered_user = Spree::User.find_by_email(params[:order][:email])
params[:order][:guest_checkout] = registered_user.nil?
return unless registered_user
@order.user_id = registered_user.id
end
end
end
end
end

View File

@@ -1,49 +0,0 @@
Spree::Admin::Orders::CustomerDetailsController.class_eval do
before_filter :check_authorization
before_filter :set_guest_checkout_status, only: :update
def update
if @order.update_attributes(params[:order])
if params[:guest_checkout] == "false"
@order.associate_user!(Spree.user_class.find_by_email(@order.email))
end
AdvanceOrderService.new(@order).call
@order.shipments.map &:refresh_rates
flash[:success] = Spree.t('customer_details_updated')
redirect_to admin_order_customer_path(@order)
else
render action: :edit
end
end
# Inherit CanCan permissions for the current order
def model_class
load_order unless @order
@order
end
private
def check_authorization
load_order
session[:access_token] ||= params[:token]
resource = @order
action = params[:action].to_sym
action = :edit if action == :show # show route renders :edit for this controller
authorize! action, resource, session[:access_token]
end
def set_guest_checkout_status
registered_user = Spree::User.find_by_email(params[:order][:email])
params[:order][:guest_checkout] = registered_user.nil?
return unless registered_user
@order.user_id = registered_user.id
end
end

View File

@@ -0,0 +1,150 @@
require 'open_food_network/spree_api_key_loader'
module Spree
module Admin
class OrdersController < Spree::Admin::BaseController
require 'spree/core/gateway_error'
include OpenFoodNetwork::SpreeApiKeyLoader
helper CheckoutHelper
before_filter :load_order, only: [:edit, :update, :fire, :resend,
:invoice, :print, :print_ticket]
before_filter :load_distribution_choices, only: [:new, :edit, :update]
# Ensure that the distributor is set for an order when
before_filter :ensure_distribution, only: :new
# After updating an order, the fees should be updated as well
# Currently, adding or deleting line items does not trigger updating the
# fees! This is a quick fix for that.
# TODO: update fees when adding/removing line items
# instead of the update_distribution_charge method.
after_filter :update_distribution_charge, only: :update
before_filter :require_distributor_abn, only: :invoice
respond_to :html, :json
def new
@order = Order.create
@order.created_by = try_spree_current_user
@order.save
redirect_to edit_admin_order_url(@order)
end
def edit
@order.shipments.map(&:refresh_rates)
AdvanceOrderService.new(@order).call
# The payment step shows an error of 'No pending payments'
# Clearing the errors from the order object will stop this error
# appearing on the edit page where we don't want it to.
@order.errors.clear
end
def update
unless @order.update_attributes(params[:order]) && @order.line_items.present?
if @order.line_items.empty?
@order.errors.add(:line_items, Spree.t('errors.messages.blank'))
end
return redirect_to(edit_admin_order_path(@order),
flash: { error: @order.errors.full_messages.join(', ') })
end
@order.update!
if @order.complete?
redirect_to edit_admin_order_path(@order)
else
# Jump to next step if order is not complete
redirect_to admin_order_customer_path(@order)
end
end
def bulk_management
load_spree_api_key
end
def fire
event = params[:e]
if @order.public_send(event.to_s)
flash[:success] = Spree.t(:order_updated)
else
flash[:error] = Spree.t(:cannot_perform_operation)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message.to_s
ensure
redirect_to :back
end
def resend
Spree::OrderMailer.confirm_email_for_customer(@order.id, true).deliver
flash[:success] = t(:order_email_resent)
respond_with(@order) { |format| format.html { redirect_to :back } }
end
def invoice
pdf = InvoiceRenderer.new.render_to_string(@order)
Spree::OrderMailer.invoice_email(@order.id, pdf).deliver
flash[:success] = t('admin.orders.invoice_email_sent')
respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
end
def print
render InvoiceRenderer.new.args(@order)
end
def print_ticket
render template: "spree/admin/orders/ticket", layout: false
end
def update_distribution_charge
@order.update_distribution_charge!
end
private
def load_order
@order = Order.find_by_number!(params[:id], include: :adjustments) if params[:id]
authorize! action, @order
end
def model_class
Spree::Order
end
def require_distributor_abn
return if @order.distributor.abn.present?
flash[:error] = t(:must_have_valid_business_number,
enterprise_name: @order.distributor.name)
respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
end
def load_distribution_choices
@shops = Enterprise.is_distributor.managed_by(spree_current_user).by_name
ocs = OrderCycle.managed_by(spree_current_user)
@order_cycles = ocs.soonest_closing +
ocs.soonest_opening +
ocs.closed +
ocs.undated
end
def ensure_distribution
unless @order
@order = Spree::Order.new
@order.generate_order_number
@order.save!
end
return if @order.distribution_set?
render 'set_distribution', locals: { order: @order }
end
end
end
end

View File

@@ -1,120 +0,0 @@
require 'open_food_network/spree_api_key_loader'
Spree::Admin::OrdersController.class_eval do
include OpenFoodNetwork::SpreeApiKeyLoader
helper CheckoutHelper
before_filter :load_order, only: %i[show edit update fire resend invoice print print_ticket]
before_filter :load_distribution_choices, only: [:new, :edit, :update]
# Ensure that the distributor is set for an order when
before_filter :ensure_distribution, only: :new
# After updating an order, the fees should be updated as well
# Currently, adding or deleting line items does not trigger updating the
# fees! This is a quick fix for that.
# TODO: update fees when adding/removing line items
# instead of the update_distribution_charge method.
after_filter :update_distribution_charge, only: :update
before_filter :require_distributor_abn, only: :invoice
respond_to :html, :json
def index
# Overriding the action so we only render the page template. An angular request
# within the page then fetches the data it needs from Api::OrdersController
end
def bulk_management
load_spree_api_key
end
def edit
@order.shipments.map &:refresh_rates
AdvanceOrderService.new(@order).call
# The payment step shows an error of 'No pending payments'
# Clearing the errors from the order object will stop this error
# appearing on the edit page where we don't want it to.
@order.errors.clear
end
# Re-implement spree method so that it redirects to edit instead of rendering edit
# This allows page reloads while adding variants to the order (/edit), without being redirected to customer details page (/update)
def update
unless @order.update_attributes(params[:order]) && @order.line_items.present?
@order.errors.add(:line_items, Spree.t('errors.messages.blank')) if @order.line_items.empty?
return redirect_to edit_admin_order_path(@order), flash: { error: @order.errors.full_messages.join(', ') }
end
@order.update!
if @order.complete?
redirect_to edit_admin_order_path(@order)
else
# Jump to next step if order is not complete
redirect_to admin_order_customer_path(@order)
end
end
# Overwrite to use confirm_email_for_customer instead of confirm_email.
# This uses a new template. See mailers/spree/order_mailer_decorator.rb.
def resend
Spree::OrderMailer.confirm_email_for_customer(@order.id, true).deliver
flash[:success] = t(:order_email_resent)
respond_with(@order) { |format| format.html { redirect_to :back } }
end
def invoice
pdf = InvoiceRenderer.new.render_to_string(@order)
Spree::OrderMailer.invoice_email(@order.id, pdf).deliver
flash[:success] = t('admin.orders.invoice_email_sent')
respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
end
def print
render InvoiceRenderer.new.args(@order)
end
def print_ticket
render template: "spree/admin/orders/ticket", layout: false
end
def update_distribution_charge
@order.update_distribution_charge!
end
private
def require_distributor_abn
if @order.distributor.abn.blank?
flash[:error] = t(:must_have_valid_business_number, enterprise_name: @order.distributor.name)
respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
end
end
def load_distribution_choices
@shops = Enterprise.is_distributor.managed_by(spree_current_user).by_name
ocs = OrderCycle.managed_by(spree_current_user)
@order_cycles = ocs.soonest_closing +
ocs.soonest_opening +
ocs.closed +
ocs.undated
end
def ensure_distribution
unless @order
@order = Spree::Order.new
@order.generate_order_number
@order.save!
end
unless @order.distribution_set?
render 'set_distribution', locals: { order: @order }
end
end
end

View File

@@ -0,0 +1,129 @@
# frozen_string_literal: true
module Spree
module Admin
class PaymentsController < Spree::Admin::BaseController
before_filter :load_order, except: [:show]
before_filter :load_payment, only: [:fire, :show]
before_filter :load_data
before_filter :can_transition_to_payment
respond_to :html
def index
@payments = @order.payments
redirect_to new_admin_order_payment_url(@order) if @payments.empty?
end
def new
@payment = @order.payments.build
end
def create
@payment = @order.payments.build(object_params)
load_payment_source
begin
unless @payment.save
redirect_to admin_order_payments_path(@order)
return
end
if @order.completed?
@payment.process!
flash[:success] = flash_message_for(@payment, :successfully_created)
redirect_to admin_order_payments_path(@order)
else
AdvanceOrderService.new(@order).call!
flash[:success] = Spree.t(:new_order_completed)
redirect_to edit_admin_order_url(@order)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message.to_s
redirect_to new_admin_order_payment_path(@order)
end
end
# When a user fires an event, take them back to where they came from
# (we can't use respond_override because Spree no longer uses respond_with)
def fire
event = params[:e]
return unless event && @payment.payment_source
# Because we have a transition method also called void, we do this to avoid conflicts.
event = "void_transaction" if event == "void"
if @payment.public_send("#{event}!")
flash[:success] = t(:payment_updated)
else
flash[:error] = t(:cannot_perform_operation)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message
ensure
redirect_to request.referer
end
private
def load_payment_source
if @payment.payment_method.is_a?(Spree::Gateway) &&
@payment.payment_method.payment_profiles_supported? &&
params[:card].present? &&
(params[:card] != 'new')
@payment.source = CreditCard.find_by_id(params[:card])
end
end
def object_params
if params[:payment] &&
params[:payment_source] &&
source_params = params.delete(:payment_source)[params[:payment][:payment_method_id]]
params[:payment][:source_attributes] = source_params
end
params[:payment]
end
def load_data
@amount = params[:amount] || load_order.total
# Only show payments for the order's distributor
@payment_methods = PaymentMethod.
available(:back_end).
select{ |pm| pm.has_distributor? @order.distributor }
@payment_method = if @payment && @payment.payment_method
@payment.payment_method
else
@payment_methods.first
end
@previous_cards = @order.credit_cards.with_payment_profile
end
# At this point admin should have passed through Customer Details step
# where order.next is called which leaves the order in payment step
#
# Orders in complete step also allows to access this controller
#
# Otherwise redirect user to that step
def can_transition_to_payment
return if @order.payment? || @order.complete?
flash[:notice] = Spree.t(:fill_in_customer_info)
redirect_to edit_admin_order_customer_url(@order)
end
def load_order
@order = Order.find_by_number!(params[:order_id])
authorize! action, @order
@order
end
def load_payment
@payment = Payment.find(params[:id])
end
end
end
end

View File

@@ -1,59 +0,0 @@
Spree::Admin::PaymentsController.class_eval do
append_before_filter :filter_payment_methods
def create
@payment = @order.payments.build(object_params)
if @payment.payment_method.is_a?(Spree::Gateway) && @payment.payment_method.payment_profiles_supported? && params[:card].present? && (params[:card] != 'new')
@payment.source = CreditCard.find_by_id(params[:card])
end
begin
unless @payment.save
redirect_to admin_order_payments_path(@order)
return
end
if @order.completed?
@payment.process!
flash[:success] = flash_message_for(@payment, :successfully_created)
redirect_to admin_order_payments_path(@order)
else
AdvanceOrderService.new(@order).call!
flash[:success] = Spree.t(:new_order_completed)
redirect_to edit_admin_order_url(@order)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message.to_s
redirect_to new_admin_order_payment_path(@order)
end
end
# When a user fires an event, take them back to where they came from
# (we can't use respond_override because Spree no longer uses respond_with)
def fire
event = params[:e]
return unless event && @payment.payment_source
# Because we have a transition method also called void, we do this to avoid conflicts.
event = "void_transaction" if event == "void"
if @payment.public_send("#{event}!")
flash[:success] = t(:payment_updated)
else
flash[:error] = t(:cannot_perform_operation)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message
ensure
redirect_to request.referer
end
private
# Only show payments for the order's distributor
def filter_payment_methods
@payment_methods = @payment_methods.select{ |pm| pm.has_distributor? @order.distributor }
@payment_method ||= @payment_methods.first
end
end

View File

@@ -0,0 +1,43 @@
module Spree
module Admin
class SearchController < Spree::Admin::BaseController
# http://spreecommerce.com/blog/2010/11/02/json-hijacking-vulnerability/
before_filter :check_json_authenticity, only: :index
respond_to :json
def known_users
@users = if exact_match = Spree.user_class.find_by_email(params[:q])
[exact_match]
else
spree_current_user.known_users.ransack(ransack_hash).result.limit(10)
end
render json: @users, each_serializer: ::Api::Admin::UserSerializer
end
def customers
@customers = []
if spree_current_user.enterprises.pluck(:id).include? params[:distributor_id].to_i
@customers = Customer.
ransack(m: 'or', email_start: params[:q], name_start: params[:q]).
result.
where(enterprise_id: params[:distributor_id])
end
render json: @customers, each_serializer: ::Api::Admin::CustomerSerializer
end
private
def ransack_hash
{
m: 'or',
email_start: params[:q],
ship_address_firstname_start: params[:q],
ship_address_lastname_start: params[:q],
bill_address_firstname_start: params[:q],
bill_address_lastname_start: params[:q]
}
end
end
end
end

View File

@@ -1,36 +0,0 @@
Spree::Admin::SearchController.class_eval do
def known_users
@users = if exact_match = Spree.user_class.find_by_email(params[:q])
[exact_match]
else
spree_current_user.known_users.ransack(
m: 'or',
email_start: params[:q],
ship_address_firstname_start: params[:q],
ship_address_lastname_start: params[:q],
bill_address_firstname_start: params[:q],
bill_address_lastname_start: params[:q]
).result.limit(10)
end
render json: @users, each_serializer: Api::Admin::UserSerializer
end
def customers
@customers = if spree_current_user.enterprises.pluck(:id).include? params[:distributor_id].to_i
Customer.ransack(m: 'or', email_start: params[:q], name_start: params[:q])
.result.where(enterprise_id: params[:distributor_id])
else
[]
end
render json: @customers, each_serializer: Api::Admin::CustomerSerializer
end
def users_with_ams
users_without_ams
render json: @users, each_serializer: Api::Admin::UserSerializer
end
alias_method_chain :users, :ams
end

View File

@@ -71,7 +71,7 @@ module Spree
@order = order_to_update
unless @order
flash[:error] = t(:order_not_found)
redirect_to(root_path) && return
redirect_to(main_app.root_path) && return
end
if @order.update_attributes(params[:order])

View File

@@ -32,7 +32,7 @@ module Spree
session[:guest_token] = nil
end
redirect_back_or_default(root_url)
redirect_back_or_default(main_app.root_url)
else
render :new
end

View File

@@ -1,6 +1,17 @@
module Spree
module Admin
module OrdersHelper
def event_links
links = []
links << event_link("cancel") if @order.can_cancel?
links << event_link("resume") if @order.can_resume?
links.join('&nbsp;').html_safe
end
def line_item_shipment_price(line_item, quantity)
Spree::Money.new(line_item.price * quantity, currency: line_item.currency)
end
def order_links(order)
@order ||= order
links = []
@@ -100,6 +111,14 @@ module Spree
icon: 'icon-trash',
confirm: t(:are_you_sure) }
end
def event_link(event)
button_link_to(Spree.t(event),
fire_admin_order_url(@order, e: event),
method: :put,
icon: "icon-#{event}",
data: { confirm: Spree.t(:order_sure_want_to, event: Spree.t(event)) })
end
end
end
end

View File

@@ -0,0 +1,11 @@
module Spree
module Admin
module PaymentsHelper
def payment_method_name(payment)
# hack to allow us to retrieve the name of a "deleted" payment method
id = payment.payment_method_id
Spree::PaymentMethod.find_with_destroyed(id).name
end
end
end
end

View File

@@ -9,6 +9,6 @@ Spree::BaseMailer.class_eval do
def roadie_options
# This lets us specify assets using relative paths in email templates
super.merge(url_options: { host: URI(spree.root_url).host })
super.merge(url_options: { host: URI(main_app.root_url).host })
end
end

View File

@@ -25,7 +25,8 @@ class Enterprise < ActiveRecord::Base
has_many :relationships_as_child, class_name: 'EnterpriseRelationship',
foreign_key: 'child_id',
dependent: :destroy
has_and_belongs_to_many :groups, class_name: 'EnterpriseGroup'
has_and_belongs_to_many :groups, join_table: 'enterprise_groups_enterprises',
class_name: 'EnterpriseGroup'
has_many :producer_properties, foreign_key: 'producer_id'
has_many :properties, through: :producer_properties
has_many :supplied_products, class_name: 'Spree::Product',
@@ -115,7 +116,10 @@ class Enterprise < ActiveRecord::Base
scope :not_ready_for_checkout, lambda {
# When ready_for_checkout is empty, return all rows when there are no enterprises ready for
# checkout.
ready_enterprises = Enterprise.ready_for_checkout.select('enterprises.id')
ready_enterprises = Enterprise.ready_for_checkout.
except(:select).
select('DISTINCT enterprises.id')
if ready_enterprises.present?
where("enterprises.id NOT IN (?)", ready_enterprises)
else

View File

@@ -5,7 +5,7 @@ class EnterpriseGroup < ActiveRecord::Base
include PermalinkGenerator
acts_as_list
has_and_belongs_to_many :enterprises
has_and_belongs_to_many :enterprises, join_table: 'enterprise_groups_enterprises'
belongs_to :owner, class_name: 'Spree::User', foreign_key: :owner_id, inverse_of: :owned_groups
belongs_to :address, class_name: 'Spree::Address'
accepts_nested_attributes_for :address

View File

@@ -63,7 +63,7 @@ class OrderCycle < ActiveRecord::Base
if user.has_spree_role?('admin')
scoped
else
where('coordinator_id IN (?)', user.enterprises.map(&:id))
where(coordinator_id: user.enterprises)
end
}

View File

@@ -0,0 +1,37 @@
# frozen_string_literal: true
class OrderCycleWarning
def initialize(current_user)
@current_user = current_user
end
def call
distributors = active_distributors_not_ready_for_checkout
return if distributors.empty?
active_distributors_not_ready_for_checkout_message(distributors)
end
private
attr_reader :current_user
def active_distributors_not_ready_for_checkout
ocs = OrderCycle.managed_by(current_user).active
distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq
Enterprise.where(id: distributors.map(&:id)).not_ready_for_checkout
end
def active_distributors_not_ready_for_checkout_message(distributors)
distributor_names = distributors.map(&:name).join ', '
if distributors.count > 1
I18n.t(:active_distributors_not_ready_for_checkout_message_plural,
distributor_names: distributor_names)
else
I18n.t(:active_distributors_not_ready_for_checkout_message_singular,
distributor_names: distributor_names)
end
end
end

View File

@@ -54,7 +54,7 @@
.row{ ng: { show: "Enterprise.sells == 'own' || Enterprise.sells == 'any'" } }
.three.columns.alpha
= f.label :permalink, t('.permalink')
%div{'ofn-with-tip' => t('.permalink_tip', link: spree.root_url)}
%div{'ofn-with-tip' => t('.permalink_tip', link: main_app.root_url)}
%a= t('admin.whats_this')
.six.columns
= f.text_field :permalink, { 'ng-model' => "Enterprise.permalink", placeholder: "eg. your-shop-name", 'ng-model-options' => "{ updateOn: 'default blur', debounce: {'default': 300, 'blur': 0} }" }
@@ -69,7 +69,7 @@
%div{'ofn-with-tip' => t('.link_to_front_tip')}
%a= t('admin.whats_this')
.eight.columns.omega
= surround spree.root_url, "/shop" do
= surround main_app.root_url, "/shop" do
{{Enterprise.permalink}}
.row
.three.columns.alpha

View File

@@ -42,10 +42,10 @@
%tr
%td{:align => "center"}
%p
%a{:href => "#{ URI.join(spree.root_url, Spree::Config.footer_tos_url).to_s }", :target => "_blank"}
%a{:href => "#{ URI.join(main_app.root_url, Spree::Config.footer_tos_url).to_s }", :target => "_blank"}
= t :terms_of_service
|
%a{:href => "#{ spree.root_url }"}
%a{:href => "#{ main_app.root_url }"}
= Spree::Config[:site_name]
/ | <a href="#"><unsubscribe>Unsubscribe</unsubscribe></a>
%td

View File

@@ -94,7 +94,7 @@
.row
.small-12.medium-3.medium-offset-2.columns.text-left
%a{href: root_path}
%a{href: main_app.root_path}
%img{src: ContentConfig.footer_logo.url, width: "220"}
.small-12.medium-5.columns.text-left
%p.text-small

View File

@@ -2,7 +2,7 @@
%section.top-bar-section
%ul.left
%li.ofn-logo
%a{href: root_path}
%a{href: main_app.root_path}
%img{src: ContentConfig.logo.url}
%li.powered-by
%img{src: '/favicon.ico'}

View File

@@ -5,7 +5,7 @@
%section.left
.ofn-logo
%a{href: root_path}
%a{href: main_app.root_path}
%img{src: ContentConfig.logo_mobile.url, srcset: ContentConfig.logo_mobile_svg.url, width: "75", height: "26"}
%section.right{"ng-cloak" => true}

View File

@@ -1,7 +1,7 @@
%aside.left-off-canvas-menu.show-for-medium-down{ ng: { controller: "OffcanvasCtrl" } }
%ul.off-canvas-list
%li.ofn-logo
%a{href: root_path}
%a{href: main_app.root_path}
%img{src: ContentConfig.logo_mobile.url, srcset: ContentConfig.logo_mobile_svg.url, width: "75", height: "26"}
- [*1..7].each do |menu_number|
- menu_name = "menu_#{menu_number}"

View File

@@ -9,6 +9,6 @@
.alert-box.blocked-cookies.hidden
%p= t('blocked_cookies_alert')
%a.button.allow{target: '_blank', href: "#{spree.root_url}embedded_shopfront/shopfront_session/"}
%a.button.allow{target: '_blank', href: "#{main_app.root_url}embedded_shopfront/shopfront_session/"}
= t('allow_cookies')

View File

@@ -0,0 +1,72 @@
<% if use_billing %>
<div class="field" style="position: absolute;margin-top: -15px;right: 0;">
<span data-hook="use_billing">
<%= check_box_tag 'order[use_billing]', '1', (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.same_as?(@order.ship_address)) %>
<%= label_tag 'order[use_billing]', Spree.t(:use_billing_address) %>
</span>
</div>
<% end %>
<% is_shipping_address = name == Spree.t(:shipping_address) %>
<% shipping_or_billing = is_shipping_address ? 'shipping' : 'billing' %>
<% s_or_b = is_shipping_address ? 's' : 'b' %>
<div id="<%= is_shipping_address ? 'shipping' : 'billing' %>" style="display: <%= (use_billing && (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.eql?(@order.ship_address))) ? 'none' : 'block' %>" data-hook="address_fields">
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :firstname, Spree.t(:first_name) + ':' %>
<%= f.text_field :firstname, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :lastname, Spree.t(:last_name) + ':' %>
<%= f.text_field :lastname, :class => 'fullwidth' %>
</div>
<% if Spree::Config[:company] %>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :company, Spree.t(:company) + ':' %>
<%= f.text_field :company, :class => 'fullwidth' %>
</div>
<% end %>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :address1, Spree.t(:street_address) + ':' %>
<%= f.text_field :address1, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :address2, Spree.t(:street_address_2) + ':' %>
<%= f.text_field :address2, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :city, Spree.t(:city) + ':' %>
<%= f.text_field :city, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :zipcode, Spree.t(:zip) + ':' %>
<%= f.text_field :zipcode, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :country_id, Spree.t(:country) + ':' %>
<span id="<%= s_or_b %>country">
<%= f.collection_select :country_id, available_countries, :id, :name, {}, {:class => 'select2 fullwidth'} %>
</span>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :state_id, Spree.t(:state) + ':' %>
<span id="<%= s_or_b %>state">
<%= f.text_field :state_name,
:style => "display: #{f.object.country.states.empty? ? 'block' : 'none' };",
:disabled => !f.object.country.states.empty?, :class => 'fullwidth state_name' %>
<%= f.collection_select :state_id, f.object.country.states.sort, :id, :name, {:include_blank => true}, {:class => 'select2 fullwidth', :style => "display: #{f.object.country.states.empty? ? 'none' : 'block' };", :disabled => f.object.country.states.empty?} %>
</span>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :phone, Spree.t(:phone) + ':' %>
<%= f.phone_field :phone, :class => 'fullwidth' %>
</div>
</div>
<% content_for :head do %>
<%= javascript_tag do -%>
$(document).ready(function(){
$('span#<%= s_or_b %>country .select2').on('change', function() { update_state('<%= s_or_b %>'); });
});
<% end -%>
<% end %>

View File

@@ -1,5 +0,0 @@
<div class="form-buttons filter-actions actions" data-hook="buttons">
<%= button Spree.t('actions.create'), 'icon-ok' %>
<span class="or"><%= Spree.t(:or) %></span>
<%= link_to_with_icon 'icon-remove', Spree.t('actions.cancel'), collection_url, :class => 'button' %>
</div>

View File

@@ -0,0 +1,4 @@
.form-buttons.filter-actions.actions
= button t('actions.create'), 'icon-ok'
%span.or= t(:or)
= button_link_to t('actions.cancel'), collection_url, icon: 'icon-remove'

View File

@@ -2,7 +2,6 @@
Spree.routes = <%== {
:variants_search => spree.admin_search_variants_path(:format => 'json'),
:taxons_search => main_app.api_taxons_path(:format => 'json'),
:user_search => spree.admin_search_users_path(:format => 'json'),
:orders_api => main_app.api_orders_path
}.to_json %>;
</script>

View File

@@ -0,0 +1,7 @@
$('#order_tab_summary h5#order_status').html('<%= j Spree.t(:status) %>: <%= j Spree.t(@order.state, :scope => :order_state) %>');
$('#order_tab_summary h5#order_total').html('<%= j Spree.t(:total) %>: <%= j @order.display_total.to_html %>');
<% if @order.completed? %>
$('#order_tab_summary h5#payment_status').html('<%= j Spree.t(:payment) %>: <%= j Spree.t(@order.payment_state, :scope => :payment_states, :default => [:missing, "none"]) %>');
$('#order_tab_summary h5#shipment_status').html('<%= j Spree.t(:shipment) %>: <%= j Spree.t(@order.shipment_state, :scope => :shipment_state, :default => [:missing, "none"]) %>');
<% end %>

View File

@@ -8,7 +8,7 @@
= link_to t(:account), account_path
%li{"data-hook" => "user-logout-link"}
%i.icon-signout
= link_to t(:logout), spree.logout_path
= link_to t(:logout), logout_path
%li{"data-hook" => "store-frontend-link"}
%i.icon-external-link
= link_to t(".header.store"), spree.root_path, target: "_blank"
= link_to t(".header.store"), main_app.root_path, target: "_blank"

View File

@@ -1,6 +1,6 @@
%html{ lang: "en" }
%head{"data-hook" => "admin_inside_head"}= render :partial => 'spree/admin/shared/head'
%body.admin{"data-ajax-root-path" => spree.root_path}
%body.admin{"data-ajax-root-path" => main_app.root_path}
#wrapper{"data-hook" => ""}
- if flash[:error]
.flash.error= flash[:error]

View File

@@ -9,7 +9,7 @@
= t :email_signup_confirmed_email
%p
-# Remove http:// and trailing slashes from root url if they exist
= t :email_signup_shop_html, link: link_to(spree.root_url.sub(/http:\/\//,"").sub(/\/$/,""), spree.root_url, target: '_blank')
= t :email_signup_shop_html, link: link_to(main_app.root_url.sub(/http:\/\//,"").sub(/\/$/,""), main_app.root_url, target: '_blank')
%p &nbsp;
%hr/
%p &nbsp;

View File

@@ -50,6 +50,8 @@ ca:
shipping_method_ids: "Mètodes d'enviament"
payment_method_ids: "Mètodes de Pagament"
errors:
messages:
inclusion: "no està inclòs a la llista"
models:
subscription_validator:
attributes:
@@ -700,6 +702,11 @@ ca:
enable_subscriptions_false: "Deshabilitat"
enable_subscriptions_true: "Habilitat"
shopfront_message: "Missatge de la botiga"
shopfront_message_placeholder: >
Un missatge opcional per donar la benvinguda als clients i explicar
com comprar amb vosaltres. Si s'introdueix text aquí, es mostrarà a
la pestanya d'inici quan els clients arribin per primera vegada a la
vostra botiga.
shopfront_message_link_tooltip: "Inserir / editar enllaç"
shopfront_message_link_prompt: "Introduïu un URL per inserir"
shopfront_closed_message: "Missatge de tancament de la botiga"
@@ -1101,10 +1108,13 @@ ca:
destroy_attachment_does_not_exist: "El logotip no existeix"
enterprise_promo_image:
destroy_attachment_does_not_exist: "La imatge promocional no existeix"
orders:
failed_to_update: "No s'ha pogut actualitzar la comanda"
checkout:
already_ordered:
cart: "cistella"
message_html: "Ja teniu una comanda per a aquest cicle de comanda. Consulteu %{cart} per veure els articles que heu demanat anteriorment. També podeu cancel·lar articles sempre que el cicle de comanda estigui obert."
failed: "La comanda ha fallat. Informeu-nos perquè puguem processar la vostra comanda."
shops:
hubs:
show_closed_shops: "Mostra les botigues tancades"
@@ -1935,6 +1945,7 @@ ca:
tax_category: "Categoria d'impostos"
calculator: "Calculadora"
calculator_values: "Valors de la calculadora"
calculator_settings_warning: "Si canvieu el tipus de calculadora, primer heu de desar abans de poder editar la configuració de la calculadora"
flat_percent_per_item: "Percentatge fixe (per article)"
flat_rate_per_item: "Tarifa fixa (per article)"
flat_rate_per_order: "Tarifa fixa (per comanda)"
@@ -2419,6 +2430,12 @@ ca:
severity: Severitat
description: Descripció
resolve: Resoldre
exchange_products:
load_more_products: "Carrega més productes"
load_all_products: "Carrega tots els productes"
select_all_products: "Seleccioneu tots els productes %{total_number_of_products}"
products_loaded: "%{num_of_products_loaded} de %{total_number_of_products} productes carregats"
loading_products: "Carregant productes"
tag_rules:
shipping_method_tagged_top: "Els mètodes d'enviament etiquetats"
shipping_method_tagged_bottom: "son:"
@@ -2501,6 +2518,7 @@ ca:
customer_placeholder: "consumidora@example.org"
valid_email_error: "siusplau, introduïu una adreça de correu electrònic vàlida"
subscriptions:
error_saving: "S'ha produït un error en desar la subscripció"
new:
please_select_a_shop: "Si us plau, seleccioneu una botiga"
insufficient_stock: "No hi ha prou estoc disponible, només queda %{on_hand}"
@@ -2818,6 +2836,8 @@ ca:
zipcode: Codi postal
weight: Pes (per kg)
error_user_destroy_with_orders: "No es poden esborrar usuaris amb comandes completades"
cannot_create_payment_without_payment_methods: "No podeu crear un pagament per a una comanda sense que hi hagi definit cap mètode de pagament."
please_define_payment_methods: "Primer definiu alguns mètodes de pagament."
options: "Opcions"
actions:
update: "Actualitzar"
@@ -2904,6 +2924,7 @@ ca:
capture: "Captura"
ship: "Enviament"
edit: "Editar"
order_not_updated: "La comanda no s'ha pogut actualitzar"
note: "Nota"
first: "Primer"
last: "Últim"

View File

@@ -2988,6 +2988,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using
zipcode: Postcode
weight: Weight (per kg)
error_user_destroy_with_orders: "Users with completed orders may not be deleted"
cannot_create_payment_without_payment_methods: "You cannot create a payment for an order without any payment methods defined."
please_define_payment_methods: "Please define some payment methods first."
options: "Options"
actions:

View File

@@ -701,6 +701,10 @@ en_CA:
enable_subscriptions_false: "Disabled"
enable_subscriptions_true: "Enabled"
shopfront_message: "Shopfront Message"
shopfront_message_placeholder: >
An optional message to welcome customers and explain how to shop with
you. If text is entered here it will be displayed in a home tab when
customers first arrive at your shopfront.
shopfront_message_link_tooltip: "Insert/edit link"
shopfront_message_link_prompt: "Please enter a URL to insert"
shopfront_closed_message: "Shopfront Closed Message"
@@ -1107,6 +1111,7 @@ en_CA:
already_ordered:
cart: "cart"
message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open."
failed: "The checkout failed. Please let us know so that we can process your order."
shops:
hubs:
show_closed_shops: "Show closed shops"
@@ -1937,6 +1942,7 @@ en_CA:
tax_category: "Tax Category"
calculator: "Calculator"
calculator_values: "Calculator values"
calculator_settings_warning: "If you are changing the calculator type, you must save first before you can edit the calculator settings"
flat_percent_per_item: "Flat Percent (per item)"
flat_rate_per_item: "Flat Rate (per item)"
flat_rate_per_order: "Flat Rate (per order)"

View File

@@ -2830,6 +2830,8 @@ en_FR:
zipcode: Postcode
weight: Weight (per kg)
error_user_destroy_with_orders: "Users with completed orders may not be deleted"
cannot_create_payment_without_payment_methods: "You cannot create a payment for an order without any payment methods defined."
please_define_payment_methods: "Please define some payment methods first."
options: "Options"
actions:
update: "Update"

View File

@@ -701,6 +701,10 @@ en_GB:
enable_subscriptions_false: "Disabled"
enable_subscriptions_true: "Enabled"
shopfront_message: "Shopfront Message"
shopfront_message_placeholder: >
An optional message to welcome customers and explain how to shop with
you. If text is entered here it will be displayed in a home tab when
customers first arrive at your shopfront.
shopfront_message_link_tooltip: "Insert / edit link"
shopfront_message_link_prompt: "Please enter a URL to insert"
shopfront_closed_message: "Shopfront Closed Message"
@@ -1107,6 +1111,7 @@ en_GB:
already_ordered:
cart: "cart"
message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open."
failed: "The checkout failed. Please let us know so that we can process your order."
shops:
hubs:
show_closed_shops: "Show closed shops"

View File

@@ -2860,6 +2860,8 @@ fr:
zipcode: Code postal
weight: Poids (au kg)
error_user_destroy_with_orders: "Les utilisateurs avec des commandes finalisées pourraient ne pas être supprimés"
cannot_create_payment_without_payment_methods: "Vous ne pouvez pas ajouter un paiement pour une commande sans avoir défini de méthode de paiement au préalable."
please_define_payment_methods: "Il faut que vous définissiez une méthode de paiement avant tout !"
options: "Options"
actions:
update: "Mettre à jour"

View File

@@ -703,6 +703,11 @@ fr_CA:
enable_subscriptions_false: "Désactivée"
enable_subscriptions_true: "Activée"
shopfront_message: "Message d'accueil de la boutique ouverte"
shopfront_message_placeholder: >
Vous pouvez indiquer ici un message de bienvenue ou un message expliquant
les particularités de votre boutique. Ce message s'affiche dans l'onglet
Accueil de votre boutique. Si aucun message n'est affiché, l'onglet
Accueil n'apparaitra pas.
shopfront_message_link_tooltip: "Insérer / modifier un lien"
shopfront_message_link_prompt: "Veuillez entrer l'URL à insérer"
shopfront_closed_message: "Message d'accueil de la boutique fermée"
@@ -1102,10 +1107,13 @@ fr_CA:
destroy_attachment_does_not_exist: "Aucun logo trouvé "
enterprise_promo_image:
destroy_attachment_does_not_exist: "Aucune bannière trouvée "
orders:
failed_to_update: "La mise à jour de la commande échoué"
checkout:
already_ordered:
cart: "panier"
message_html: "Vous avez déjà passé une commande pour ce cycle de vente. Vérifiez votre %{cart} pour voir les produits commandés. Vous pouvez annuler ou modifier votre commande jusqu'à la fermeture du cycle de vente."
failed: "La validation du paiement a échoué. Contactez-nous afin de finaliser votre commande."
shops:
hubs:
show_closed_shops: "Afficher les boutiques fermées"
@@ -1936,6 +1944,7 @@ fr_CA:
tax_category: "Type de taxe "
calculator: "Calculateur"
calculator_values: "Valeurs applicables"
calculator_settings_warning: "Si vous modifiez le type de calculateur, vous devez sauvegarder avant de modifier les paramètres du calculateur."
flat_percent_per_item: "Pourcentage net"
flat_rate_per_item: "Taux forfaitaire par article"
flat_rate_per_order: "Montant fixe par commande"
@@ -2920,6 +2929,7 @@ fr_CA:
capture: "Payée"
ship: "Expédier"
edit: "Modifier"
order_not_updated: "La commande n'a pas pu être mise à jour"
note: "Note"
first: "Début"
last: "Fin"

View File

@@ -701,6 +701,10 @@ nb:
enable_subscriptions_false: "Deaktivert"
enable_subscriptions_true: "Aktivert"
shopfront_message: "Melding Butikk"
shopfront_message_placeholder: >
En valgfri melding for å ønske kunder velkommen og forklare hvordan
de handler hos deg. Hvis tekst legges inn her, vil den vises i en hjemmefane
når kundene først ankommer butikken din.
shopfront_message_link_tooltip: "Sett inn / rediger lenke"
shopfront_message_link_prompt: "Vennligst skriv inn en URL for å sette inn"
shopfront_closed_message: "Melding Butikk Stengt"
@@ -1107,6 +1111,7 @@ nb:
already_ordered:
cart: "handlekurv"
message_html: "Du har allerede en bestilling for denne bestillingsrunden. Sjekk %{cart}en for å se varene du bestilte før. Du kan også avbryte varer så lenge bestillingsrunden er åpen."
failed: "Utsjekk fra kassen mislyktes. Gi oss beskjed slik at vi kan behandle bestillingen din."
shops:
hubs:
show_closed_shops: "Vis stengte butikker"
@@ -2824,6 +2829,8 @@ nb:
zipcode: Postnummer
weight: Vekt (per kg)
error_user_destroy_with_orders: "Brukere med fullførte ordrer kan ikke slettes"
cannot_create_payment_without_payment_methods: "Du kan ikke opprette en betaling for en bestilling uten at det er definert noen betalingsmetoder."
please_define_payment_methods: "Vennligst angi noen betalingsmetoder først."
options: "Valg"
actions:
update: "Oppdater"

View File

@@ -50,7 +50,6 @@ Spree::Core::Engine.routes.draw do
namespace :admin do
get '/search/known_users' => "search#known_users", :as => :search_known_users
get '/search/customers' => 'search#customers', :as => :search_customers
get '/search/customer_addresses' => 'search#customer_addresses', :as => :search_customer_addresses
resources :users
@@ -85,18 +84,32 @@ Spree::Core::Engine.routes.draw do
get '/variants/search', :to => "variants#search", :as => :search_variants
resources :orders do
get :invoice, on: :member
get :print, on: :member
get :print_ticket, on: :member
get :managed, on: :collection
member do
put :fire
get :fire
post :resend
get :invoice
get :print
get :print_ticket
end
collection do
get :managed
resources :invoices, only: [:create, :show] do
get :poll
end
end
resources :adjustments
resources :payments do
member do
put :fire
end
end
resource :customer, :controller => "orders/customer_details"
end
resources :users do

View File

@@ -77,7 +77,7 @@ module OpenFoodNetwork
ba.phone,
order.shipping_method.andand.name,
order.payments.first.andand.payment_method.andand.name,
order.payments.first.amount,
order.payment_total,
OpenFoodNetwork::UserBalanceCalculator.new(order.email, order.distributor).balance]
end
@@ -92,7 +92,7 @@ module OpenFoodNetwork
sa.phone,
order.shipping_method.andand.name,
order.payments.first.andand.payment_method.andand.name,
order.payments.first.amount,
order.payment_total,
OpenFoodNetwork::UserBalanceCalculator.new(order.email, order.distributor).balance,
has_temperature_controlled_items?(order),
order.special_instructions]

View File

@@ -6,25 +6,13 @@ module OpenFoodNetwork
end
def balance
payment_total - completed_order_total
-completed_orders.sum(&:outstanding_balance)
end
private
def completed_order_total
completed_orders.sum(&:total)
end
def payment_total
payments.sum(&:amount)
end
def completed_orders
Spree::Order.where(distributor_id: @distributor, email: @email).complete.not_state(:canceled)
end
def payments
Spree::Payment.where(order_id: completed_orders, state: "completed")
end
end
end

View File

@@ -1,5 +1,5 @@
Spree::Core::ControllerHelpers::Auth.class_eval do
def require_login_then_redirect_to(url)
redirect_to root_path(anchor: "login?after_login=#{url}")
redirect_to main_app.root_path(anchor: "login?after_login=#{url}")
end
end

View File

@@ -9,6 +9,9 @@ namespace :ofn do
sql_delete_from "
spree_inventory_units #{where_order_id_in_orders_to_delete}"
sql_delete_from "
spree_inventory_units
where shipment_id in (select id from spree_shipments #{where_order_id_in_orders_to_delete})"
truncate_adjustments

View File

@@ -13,31 +13,6 @@ describe Spree::Admin::BaseController, type: :controller do
expect(response).to redirect_to root_path(anchor: "login?after_login=/spree/admin/base")
end
describe "displaying error messages for active distributors not ready for checkout" do
it "generates an error message when there is one distributor" do
distributor = double(:distributor, name: 'My Hub')
expect(controller.
send(:active_distributors_not_ready_for_checkout_message, [distributor])).
to eq(
"The hub My Hub is listed in an active order cycle, " \
"but does not have valid shipping and payment methods. " \
"Until you set these up, customers will not be able to shop at this hub."
)
end
it "generates an error message when there are several distributors" do
d1 = double(:distributor, name: 'Hub One')
d2 = double(:distributor, name: 'Hub Two')
expect(controller.
send(:active_distributors_not_ready_for_checkout_message, [d1, d2])).
to eq(
"The hubs Hub One, Hub Two are listed in an active order cycle, " \
"but do not have valid shipping and payment methods. " \
"Until you set these up, customers will not be able to shop at these hubs."
)
end
end
describe "rendering as json ActiveModelSerializer" do
context "when data is an object" do
let(:data) { { attr: 'value' } }

View File

@@ -369,7 +369,12 @@ feature '
find(:css, "tags-input .tags input").set "wholesale\n"
end
page.all("table.exchanges tr.distributor td.products").each(&:click)
exchange_rows = page.all("table.exchanges tbody")
exchange_rows.each do |exchange_row|
exchange_row.find("td.products").click
# Wait for the products panel to be visible.
expect(exchange_row).to have_selector "tr", count: 2
end
uncheck "order_cycle_outgoing_exchange_2_variants_#{v1.id}"
check "order_cycle_outgoing_exchange_2_variants_#{v2.id}"

View File

@@ -69,7 +69,7 @@ module OpenFoodNetwork
create(:order_with_totals_and_distribution,
user: user1, distributor: hub1,
completed_at: 1.day.ago, state: "canceled")
} # total=10
} # total=13 (10 + 3 shipping fee)
let!(:p4) {
create(:payment, order: o4, amount: 20.00,
state: "completed")
@@ -79,6 +79,62 @@ module OpenFoodNetwork
expect(UserBalanceCalculator.new(o4.email, hub1).balance).to eq(-9) # = 15 + 2 - 13 - 13
end
end
context "with void payments" do
let!(:o4) {
create(:order_with_totals_and_distribution,
user: user1, distributor: hub1,
completed_at: 1.day.ago)
} # total=13 (10 + 3 shipping fee)
let!(:p4) {
create(:payment, order: o4, amount: 20.00,
state: "void")
}
it "does not include void in the balance" do
expect(UserBalanceCalculator.new(o4.email, hub1).balance).to eq(-22) # = 15 + 2 - 13 - 13 - 10
end
end
context "with invalid payments" do
let!(:o4) {
create(:order_with_totals_and_distribution,
user: user1, distributor: hub1,
completed_at: 1.day.ago)
} # total=13 (10 + 3 shipping fee)
let!(:p4) {
create(:payment, order: o4, amount: 20.00,
state: "invalid")
}
it "does not include invalid payments in the balance" do
expect(UserBalanceCalculator.new(o4.email, hub1).balance).to eq(-22) # = 15 + 2 - 13 - 13 - 10
end
end
context "with multiple payments on single order" do
let!(:o4) {
create(:order_with_totals_and_distribution,
user: user1, distributor: hub1,
completed_at: 1.day.ago)
} # total=13 (10 + 3 shipping fee)
let!(:p4) {
create(:payment, order: o4, amount: 4.00,
state: "completed")
}
let!(:p5) {
create(:payment, order: o4, amount: 5.00,
state: "completed")
}
let!(:p6) {
create(:payment, order: o4, amount: 6.00,
state: "completed")
}
it "includes orders with multiple payments in the balance" do
expect(UserBalanceCalculator.new(o4.email, hub1).balance).to eq(-7) # = 15 + 2 + 4 + 5 + 6 - 13 - 13 - 10
end
end
end
end
end

View File

@@ -0,0 +1,31 @@
require 'spec_helper'
describe OrderCycleWarning do
let(:user) { create(:user) }
let(:subject) { OrderCycleWarning }
let!(:distributor) { create(:enterprise, owner: user) }
let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor]) }
describe "checking if user's managed order cycles have distributors not ready for checkout" do
context "with an invalid distributor" do
it "returns a warning message" do
expect(subject.new(user).call).to eq(
I18n.t(:active_distributors_not_ready_for_checkout_message_singular,
distributor_names: distributor.name)
)
end
end
context "with a valid distributor" do
let!(:distributor) {
create(:distributor_enterprise,
shipping_methods: [create(:shipping_method)],
payment_methods: [create(:payment_method)])
}
it "returns nil" do
expect(subject.new(user).call).to eq nil
end
end
end
end

41
vendor/assets/javascripts/equalize.js vendored Normal file
View File

@@ -0,0 +1,41 @@
/**
* equalize.js
* Author & copyright (c) 2012: Tim Svensen
* Dual MIT & GPL license
*
* Page: http://tsvensen.github.com/equalize.js
* Repo: https://github.com/tsvensen/equalize.js/
*
* The jQuery plugin for equalizing the height or width of elements.
*
* Equalize will accept any of the jQuery Dimension methods:
* height, outerHeight, innerHeight,
* width, outerWidth, innerWidth.
*
* EXAMPLE
* $('.parent').equalize(); // defaults to 'height'
* $('.parent').equalize('width'); // equalize the widths
*/
(function($, window, document, undefined) {
$.fn.equalize = function(equalize) {
var $containers = this, // this is the jQuery object
equalize = equalize || 'height',
type = (equalize.indexOf('eight') > 0) ? 'height' : 'width';
if (!$.isFunction($.fn[equalize])) { return false; }
return $containers.each(function() {
var $children = $(this).children(),
max = 0; // reset for each container
$children.each(function() {
var value = $(this)[equalize](); // call height(), outerHeight(), etc.
if (value > max) { max = value; } // update max
});
$children.css(type, max +'px'); // add CSS to children
});
};
}(jQuery, window, document));

41
vendor/assets/javascripts/jquery.cookie.js vendored Executable file
View File

@@ -0,0 +1,41 @@
/**
* jQuery Cookie plugin
*
* Copyright (c) 2010 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
jQuery.cookie = function (key, value, options) {
// key and at least value given, set cookie...
if (arguments.length > 1 && String(value) !== "[object Object]") {
options = jQuery.extend({}, options);
if (value === null || value === undefined) {
options.expires = -1;
}
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setDate(t.getDate() + days);
}
value = String(value);
return (document.cookie = [
encodeURIComponent(key), '=',
options.raw ? value : encodeURIComponent(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// key and possibly options given, get cookie...
options = value || {};
var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent;
return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
};

View File

@@ -0,0 +1,141 @@
/**
* jQuery Horizontal Navigation 1.0
* https://github.com/sebnitu/horizontalNav
*
* By Sebastian Nitu - Copyright 2012 - All rights reserved
* Author URL: http://sebnitu.com
*/
(function($) {
$.fn.horizontalNav = function(options) {
// Extend our default options with those provided.
var opts = $.extend({}, $.fn.horizontalNav.defaults, options);
return this.each(function () {
// Save our object
var $this = $(this);
// Build element specific options
// This lets me access options with this syntax: o.optionName
var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
// Save the wrapper. The wrapper is the element that
// we figure out what the full width should be
if ($this.is('ul')) {
var ul_wrap = $this.parent();
} else {
var ul_wrap = $this;
}
// let's append a clearfixing element to the ul wrapper
ul_wrap.css({ 'zoom' : '1' }).append('<div class="clearHorizontalNav">');
$('.clearHorizontalNav').css({
'display' : 'block',
'overflow' : 'hidden',
'visibility' : 'hidden',
'width' : 0,
'height' : 0,
'clear' : 'both'
});
// Grab elements we'll need and add some default styles
var ul = $this.is('ul') ? $this : ul_wrap.find('> ul'), // The unordered list element
li = ul.find('> li'), // All list items
li_last = li.last(), // Last list item
li_count = li.size(), // The number of navigation elements
li_a = li.find('> a'); // Remove padding from the links
// If set to responsive, re-construct after every browser resize
if ( o.responsive === true ) {
// Only need to do this for IE7 and below
// or if we set tableDisplay to false
if ( (o.tableDisplay != true) || ($.browser.msie && parseInt($.browser.version, 10) <= 7) ) {
resizeTrigger( _construct, o.responsiveDelay );
}
}
// Initiate the plugin
_construct();
// Returns the true inner width of an element
// Essentially it's the inner width without padding.
function trueInnerWidth(element) {
return element.innerWidth() - (
parseInt(element.css('padding-left')) + parseInt(element.css('padding-right'))
);
}
// Call funcion on browser resize
function resizeTrigger(callback, delay) {
// Delay before function is called
delay = delay || 100;
// Call function on resize
var resizeTimer;
$(window).resize(function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
callback();
}, delay);
});
}
// The heavy lifting of this plugin. This is where we
// find and set the appropriate widths for list items
function _construct() {
if ( (o.tableDisplay != true) || ($.browser.msie && parseInt($.browser.version, 10) <= 7) ) {
// IE7 doesn't support the "display: table" method
// so we need to do it the hard way.
// Add some styles
ul.css({ 'float' : 'left' });
li.css({ 'float' : 'left', 'width' : 'auto' });
li_a.css({ 'padding-left' : 0, 'padding-right' : 0 });
// Grabbing widths and doing some math
var ul_width = trueInnerWidth(ul),
ul_width_outer = ul.outerWidth(true),
ul_width_extra = ul_width_outer - ul_width,
full_width = trueInnerWidth(ul_wrap),
extra_width = (full_width - ul_width_extra) - ul_width,
li_padding = Math.floor( extra_width / li_count );
// Cycle through the list items and give them widths
li.each(function(index) {
var li_width = trueInnerWidth( $(this) );
$(this).css({ 'width' : (li_width + li_padding) + 'px' });
});
// Get the leftover pixels after we set every itms width
var li_last_width = trueInnerWidth(li_last) + ( (full_width - ul_width_extra) - trueInnerWidth(ul) );
// I hate to do this but for some reason Firefox (v13.0) and IE are always
// one pixel off when rendering. So this is a quick fix for that.
if ($.browser.mozilla || $.browser.msie) {
li_last_width = li_last_width - 1;
}
// Add the leftovers to the last navigation item
li_last.css({ 'width' : li_last_width + 'px' });
} else {
// Every modern browser supports the "display: table" method
// so this is the best way to do it for them.
ul.css({ 'display' : 'table', 'float' : 'none', 'width' : '100%' });
li.css({ 'display' : 'table-cell', 'float' : 'none' });
}
}
}); // @end of return this.each()
};
$.fn.horizontalNav.defaults = {
responsive : true,
responsiveDelay : 100,
tableDisplay : true
};
})(jQuery);

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

View File

@@ -0,0 +1,61 @@
/*
* jsTree apple theme 1.0
* Supported features: dots/no-dots, icons/no-icons, focused, loading
* Supported plugins: ui (hovered, clicked), checkbox, contextmenu, search
*/
.jstree-apple > ul { background:url("bg.jpg") left top repeat; }
.jstree-apple li,
.jstree-apple ins { background-image:url("d.png"); background-repeat:no-repeat; background-color:transparent; }
.jstree-apple li { background-position:-90px 0; background-repeat:repeat-y; }
.jstree-apple li.jstree-last { background:transparent; }
.jstree-apple .jstree-open > ins { background-position:-72px 0; }
.jstree-apple .jstree-closed > ins { background-position:-54px 0; }
.jstree-apple .jstree-leaf > ins { background-position:-36px 0; }
.jstree-apple a { border-radius:4px; -webkit-border-radius:4px; text-shadow:1px 1px 1px white; }
.jstree-apple .jstree-hovered { background:#e7f4f9; border:1px solid #d8f0fa; padding:0 3px 0 1px; text-shadow:1px 1px 1px silver; }
.jstree-apple .jstree-clicked { background:#beebff; border:1px solid #99defd; padding:0 3px 0 1px; }
.jstree-apple a .jstree-icon { background-position:-56px -20px; }
.jstree-apple a.jstree-loading .jstree-icon { background:url("throbber.gif") center center no-repeat !important; }
.jstree-apple.jstree-focused { background:white; }
.jstree-apple .jstree-no-dots li,
.jstree-apple .jstree-no-dots .jstree-leaf > ins { background:transparent; }
.jstree-apple .jstree-no-dots .jstree-open > ins { background-position:-18px 0; }
.jstree-apple .jstree-no-dots .jstree-closed > ins { background-position:0 0; }
.jstree-apple .jstree-no-icons a .jstree-icon { display:none; }
.jstree-apple .jstree-search { font-style:italic; }
.jstree-apple .jstree-no-icons .jstree-checkbox { display:inline-block; }
.jstree-apple .jstree-no-checkboxes .jstree-checkbox { display:none !important; }
.jstree-apple .jstree-checked > a > .jstree-checkbox { background-position:-38px -19px; }
.jstree-apple .jstree-unchecked > a > .jstree-checkbox { background-position:-2px -19px; }
.jstree-apple .jstree-undetermined > a > .jstree-checkbox { background-position:-20px -19px; }
.jstree-apple .jstree-checked > a > .checkbox:hover { background-position:-38px -37px; }
.jstree-apple .jstree-unchecked > a > .jstree-checkbox:hover { background-position:-2px -37px; }
.jstree-apple .jstree-undetermined > a > .jstree-checkbox:hover { background-position:-20px -37px; }
#vakata-dragged.jstree-apple ins { background:transparent !important; }
/*#vakata-dragged.jstree-apple .jstree-ok { background:url("d.png") -2px -53px no-repeat !important; }*/
/*#vakata-dragged.jstree-apple .jstree-invalid { background:url("d.png") -18px -53px no-repeat !important; }*/
/*#jstree-marker.jstree-apple { background:url("d.png") -41px -57px no-repeat !important; text-indent:-100px; }*/
.jstree-apple a.jstree-search { color:aqua; }
.jstree-apple .jstree-locked a { color:silver; cursor:default; }
#vakata-contextmenu.jstree-apple-context,
#vakata-contextmenu.jstree-apple-context li ul { background:#f0f0f0; border:1px solid #979797; -moz-box-shadow: 1px 1px 2px #999; -webkit-box-shadow: 1px 1px 2px #999; box-shadow: 1px 1px 2px #999; }
#vakata-contextmenu.jstree-apple-context li { }
#vakata-contextmenu.jstree-apple-context a { color:black; }
#vakata-contextmenu.jstree-apple-context a:hover,
#vakata-contextmenu.jstree-apple-context .vakata-hover > a { padding:0 5px; background:#e8eff7; border:1px solid #aecff7; color:black; -webkit-border-radius:2px; border-radius:2px; }
#vakata-contextmenu.jstree-apple-context li.jstree-contextmenu-disabled a,
#vakata-contextmenu.jstree-apple-context li.jstree-contextmenu-disabled a:hover { color:silver; background:transparent; border:0; padding:1px 4px; }
#vakata-contextmenu.jstree-apple-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; }
#vakata-contextmenu.jstree-apple-context li ul { margin-left:-4px; }
/* TODO: IE6 support - the `>` selectors */

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,11 @@
(function ($) {
// VERTICALLY ALIGN FUNCTION
$.fn.vAlign = function() {
return this.each(function(i){
var ah = $(this).height();
var ph = $(this).parent().height();
var mh = Math.ceil((ph-ah) / 2);
$(this).css('margin-top', mh);
});
};
})(jQuery);

319
vendor/assets/javascripts/spin.js vendored Normal file
View File

@@ -0,0 +1,319 @@
//fgnass.github.com/spin.js#v1.2.6
!function(window, document, undefined) {
/**
* Copyright (c) 2011 Felix Gnass [fgnass at neteye dot de]
* Licensed under the MIT license
*/
var prefixes = ['webkit', 'Moz', 'ms', 'O'] /* Vendor prefixes */
, animations = {} /* Animation rules keyed by their name */
, useCssAnimations
/**
* Utility function to create elements. If no tag name is given,
* a DIV is created. Optionally properties can be passed.
*/
function createEl(tag, prop) {
var el = document.createElement(tag || 'div')
, n
for(n in prop) el[n] = prop[n]
return el
}
/**
* Appends children and returns the parent.
*/
function ins(parent /* child1, child2, ...*/) {
for (var i=1, n=arguments.length; i<n; i++)
parent.appendChild(arguments[i])
return parent
}
/**
* Insert a new stylesheet to hold the @keyframe or VML rules.
*/
var sheet = function() {
var el = createEl('style', {type : 'text/css'})
ins(document.getElementsByTagName('head')[0], el)
return el.sheet || el.styleSheet
}()
/**
* Creates an opacity keyframe animation rule and returns its name.
* Since most mobile Webkits have timing issues with animation-delay,
* we create separate rules for each line/segment.
*/
function addAnimation(alpha, trail, i, lines) {
var name = ['opacity', trail, ~~(alpha*100), i, lines].join('-')
, start = 0.01 + i/lines*100
, z = Math.max(1 - (1-alpha) / trail * (100-start), alpha)
, prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase()
, pre = prefix && '-'+prefix+'-' || ''
if (!animations[name]) {
sheet.insertRule(
'@' + pre + 'keyframes ' + name + '{' +
'0%{opacity:' + z + '}' +
start + '%{opacity:' + alpha + '}' +
(start+0.01) + '%{opacity:1}' +
(start+trail) % 100 + '%{opacity:' + alpha + '}' +
'100%{opacity:' + z + '}' +
'}', sheet.cssRules.length)
animations[name] = 1
}
return name
}
/**
* Tries various vendor prefixes and returns the first supported property.
**/
function vendor(el, prop) {
var s = el.style
, pp
, i
if(s[prop] !== undefined) return prop
prop = prop.charAt(0).toUpperCase() + prop.slice(1)
for(i=0; i<prefixes.length; i++) {
pp = prefixes[i]+prop
if(s[pp] !== undefined) return pp
}
}
/**
* Sets multiple style properties at once.
*/
function css(el, prop) {
for (var n in prop)
el.style[vendor(el, n)||n] = prop[n]
return el
}
/**
* Fills in default values.
*/
function merge(obj) {
for (var i=1; i < arguments.length; i++) {
var def = arguments[i]
for (var n in def)
if (obj[n] === undefined) obj[n] = def[n]
}
return obj
}
/**
* Returns the absolute page-offset of the given element.
*/
function pos(el) {
var o = { x:el.offsetLeft, y:el.offsetTop }
while((el = el.offsetParent))
o.x+=el.offsetLeft, o.y+=el.offsetTop
return o
}
var defaults = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 5, // The line thickness
radius: 10, // The radius of the inner circle
rotate: 0, // Rotation offset
corners: 1, // Roundness (0..1)
color: '#000', // #rgb or #rrggbb
speed: 1, // Rounds per second
trail: 100, // Afterglow percentage
opacity: 1/4, // Opacity of the lines
fps: 20, // Frames per second when using setTimeout()
zIndex: 2e9, // Use a high z-index by default
className: 'spinner', // CSS class to assign to the element
top: 'auto', // center vertically
left: 'auto' // center horizontally
}
/** The constructor */
var Spinner = function Spinner(o) {
if (!this.spin) return new Spinner(o)
this.opts = merge(o || {}, Spinner.defaults, defaults)
}
Spinner.defaults = {}
merge(Spinner.prototype, {
spin: function(target) {
this.stop()
var self = this
, o = self.opts
, el = self.el = css(createEl(0, {className: o.className}), {position: 'relative', width: 0, zIndex: o.zIndex})
, mid = o.radius+o.length+o.width
, ep // element position
, tp // target position
if (target) {
target.insertBefore(el, target.firstChild||null)
tp = pos(target)
ep = pos(el)
css(el, {
left: (o.left == 'auto' ? tp.x-ep.x + (target.offsetWidth >> 1) : parseInt(o.left, 10) + mid) + 'px',
top: (o.top == 'auto' ? tp.y-ep.y + (target.offsetHeight >> 1) : parseInt(o.top, 10) + mid) + 'px'
})
}
el.setAttribute('aria-role', 'progressbar')
self.lines(el, self.opts)
if (!useCssAnimations) {
// No CSS animation support, use setTimeout() instead
var i = 0
, fps = o.fps
, f = fps/o.speed
, ostep = (1-o.opacity) / (f*o.trail / 100)
, astep = f/o.lines
;(function anim() {
i++;
for (var s=o.lines; s; s--) {
var alpha = Math.max(1-(i+s*astep)%f * ostep, o.opacity)
self.opacity(el, o.lines-s, alpha, o)
}
self.timeout = self.el && setTimeout(anim, ~~(1000/fps))
})()
}
return self
},
stop: function() {
var el = this.el
if (el) {
clearTimeout(this.timeout)
if (el.parentNode) el.parentNode.removeChild(el)
this.el = undefined
}
return this
},
lines: function(el, o) {
var i = 0
, seg
function fill(color, shadow) {
return css(createEl(), {
position: 'absolute',
width: (o.length+o.width) + 'px',
height: o.width + 'px',
background: color,
boxShadow: shadow,
transformOrigin: 'left',
transform: 'rotate(' + ~~(360/o.lines*i+o.rotate) + 'deg) translate(' + o.radius+'px' +',0)',
borderRadius: (o.corners * o.width>>1) + 'px'
})
}
for (; i < o.lines; i++) {
seg = css(createEl(), {
position: 'absolute',
top: 1+~(o.width/2) + 'px',
transform: o.hwaccel ? 'translate3d(0,0,0)' : '',
opacity: o.opacity,
animation: useCssAnimations && addAnimation(o.opacity, o.trail, i, o.lines) + ' ' + 1/o.speed + 's linear infinite'
})
if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), {top: 2+'px'}))
ins(el, ins(seg, fill(o.color, '0 0 1px rgba(0,0,0,.1)')))
}
return el
},
opacity: function(el, i, val) {
if (i < el.childNodes.length) el.childNodes[i].style.opacity = val
}
})
/////////////////////////////////////////////////////////////////////////
// VML rendering for IE
/////////////////////////////////////////////////////////////////////////
/**
* Check and init VML support
*/
;(function() {
function vml(tag, attr) {
return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr)
}
var s = css(createEl('group'), {behavior: 'url(#default#VML)'})
if (!vendor(s, 'transform') && s.adj) {
// VML support detected. Insert CSS rule ...
sheet.addRule('.spin-vml', 'behavior:url(#default#VML)')
Spinner.prototype.lines = function(el, o) {
var r = o.length+o.width
, s = 2*r
function grp() {
return css(
vml('group', {
coordsize: s + ' ' + s,
coordorigin: -r + ' ' + -r
}),
{ width: s, height: s }
)
}
var margin = -(o.width+o.length)*2 + 'px'
, g = css(grp(), {position: 'absolute', top: margin, left: margin})
, i
function seg(i, dx, filter) {
ins(g,
ins(css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}),
ins(css(vml('roundrect', {arcsize: o.corners}), {
width: r,
height: o.width,
left: o.radius,
top: -o.width>>1,
filter: filter
}),
vml('fill', {color: o.color, opacity: o.opacity}),
vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change
)
)
)
}
if (o.shadow)
for (i = 1; i <= o.lines; i++)
seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)')
for (i = 1; i <= o.lines; i++) seg(i)
return ins(el, g)
}
Spinner.prototype.opacity = function(el, i, val, o) {
var c = el.firstChild
o = o.shadow && o.lines || 0
if (c && i+o < c.childNodes.length) {
c = c.childNodes[i+o]; c = c && c.firstChild; c = c && c.firstChild
if (c) c.opacity = val
}
}
}
else
useCssAnimations = vendor(s, 'animation')
})()
if (typeof define == 'function' && define.amd)
define(function() { return Spinner })
else
window.Spinner = Spinner
}(window, document)

View File

@@ -0,0 +1,357 @@
/*
* jQuery UI CSS Framework 1.8.14
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
* jQuery UI CSS Framework 1.8.14
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Helvetica,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=2px&bgColorHeader=dddddd&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=50&borderColorHeader=dddddd&fcHeader=444444&iconColorHeader=0073ea&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=dddddd&fcContent=444444&iconColorContent=ff0084&bgColorDefault=f6f6f6&bgTextureDefault=03_highlight_soft.png&bgImgOpacityDefault=100&borderColorDefault=dddddd&fcDefault=0073ea&iconColorDefault=666666&bgColorHover=0073ea&bgTextureHover=03_highlight_soft.png&bgImgOpacityHover=25&borderColorHover=0073ea&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=dddddd&fcActive=ff0084&iconColorActive=454545&bgColorHighlight=ffffff&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=cccccc&fcHighlight=444444&iconColorHighlight=0073ea&bgColorError=ffffff&bgTextureError=01_flat.png&bgImgOpacityError=55&borderColorError=ff0084&fcError=222222&iconColorError=ff0084&bgColorOverlay=eeeeee&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=80&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=60&thicknessShadow=4px&offsetTopShadow=-4px&offsetLeftShadow=-4px&cornerRadiusShadow=0px
*/
/* Component containers
----------------------------------*/
.ui-widget { font-family: Helvetica, Arial, sans-serif; font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Helvetica, Arial, sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #dddddd; background: #ffffff url(<%= asset_path("jquery-ui/ui-bg_flat_75_ffffff_40x100.png") %>) 50% 50% repeat-x; color: #444444; }
.ui-widget-content a { color: #444444; }
.ui-widget-header { border: 1px solid #dddddd; background: #dddddd url(<%= asset_path("jquery-ui/ui-bg_highlight-soft_50_dddddd_1x100.png") %>) 50% 50% repeat-x; color: #444444; font-weight: bold; }
.ui-widget-header a { color: #444444; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #dddddd; background: #f6f6f6 url(<%= asset_path("jquery-ui/ui-bg_highlight-soft_100_f6f6f6_1x100.png") %>) 50% 50% repeat-x; font-weight: bold; color: #0073ea; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #0073ea; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #0073ea; background: #0073ea url(<%= asset_path("jquery-ui/ui-bg_highlight-soft_25_0073ea_1x100.png") %>) 50% 50% repeat-x; font-weight: bold; color: #ffffff; }
.ui-state-hover a, .ui-state-hover a:hover { color: #ffffff; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #dddddd; background: #ffffff url(<%= asset_path("jquery-ui/ui-bg_glass_65_ffffff_1x400.png") %>) 50% 50% repeat-x; font-weight: bold; color: #ff0084; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #ff0084; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #cccccc; background: #ffffff url(<%= asset_path("jquery-ui/ui-bg_flat_55_ffffff_40x100.png") %>) 50% 50% repeat-x; color: #444444; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #444444; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #ff0084; background: #ffffff url(<%= asset_path("jquery-ui/ui-bg_flat_55_ffffff_40x100.png") %>) 50% 50% repeat-x; color: #222222; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #222222; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #222222; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(<%= asset_path("jquery-ui/ui-icons_ff0084_256x240.png") %>); }
.ui-widget-content .ui-icon {background-image: url(<%= asset_path("jquery-ui/ui-icons_ff0084_256x240.png") %>); }
.ui-widget-header .ui-icon {background-image: url(<%= asset_path("jquery-ui/ui-icons_0073ea_256x240.png") %>); }
.ui-state-default .ui-icon { background-image: url(<%= asset_path("jquery-ui/ui-icons_666666_256x240.png") %>); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(<%= asset_path("jquery-ui/ui-icons_ffffff_256x240.png") %>); }
.ui-state-active .ui-icon {background-image: url(<%= asset_path("jquery-ui/ui-icons_454545_256x240.png") %>); }
.ui-state-highlight .ui-icon {background-image: url(<%= asset_path("jquery-ui/ui-icons_0073ea_256x240.png") %>); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(<%= asset_path("jquery-ui/ui-icons_ff0084_256x240.png") %>); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -webkit-border-top-left-radius: 2px; -khtml-border-top-left-radius: 2px; border-top-left-radius: 2px; }
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -webkit-border-top-right-radius: 2px; -khtml-border-top-right-radius: 2px; border-top-right-radius: 2px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -webkit-border-bottom-left-radius: 2px; -khtml-border-bottom-left-radius: 2px; border-bottom-left-radius: 2px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -webkit-border-bottom-right-radius: 2px; -khtml-border-bottom-right-radius: 2px; border-bottom-right-radius: 2px; }
/* Overlays */
.ui-widget-overlay { background: #eeeeee url(<%= asset_path("jquery-ui/ui-bg_flat_0_eeeeee_40x100.png") %>) 50% 50% repeat-x; opacity: .80;filter:Alpha(Opacity=80); }
.ui-widget-shadow { margin: -4px 0 0 -4px; padding: 4px; background: #aaaaaa url(<%= asset_path("jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png") %>) 50% 50% repeat-x; opacity: .60;filter:Alpha(Opacity=60); -khtml-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; }/*
* jQuery UI Datepicker 1.8.14
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Datepicker#theming
*/
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
display: none; /*sorry for IE5*/
display/**/: block; /*sorry for IE5*/
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}