mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-19 19:46:51 +00:00
Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be19d50639 | ||
|
|
0ceb8ab6c4 | ||
|
|
e387c7db83 | ||
|
|
d5df48f3c0 | ||
|
|
c9abdac2e0 | ||
|
|
ff08d9f210 | ||
|
|
9313a57d19 | ||
|
|
b0f2e01c70 | ||
|
|
747be81aec | ||
|
|
fd124daf50 | ||
|
|
ef33d27e6c | ||
|
|
3a01e00d7b | ||
|
|
81103f3f71 | ||
|
|
a8b48a561f | ||
|
|
c7038f6ac9 | ||
|
|
ea75714561 | ||
|
|
b7d19dd34c | ||
|
|
44d1b3f00c | ||
|
|
f8376c0aeb | ||
|
|
88464d58c2 | ||
|
|
962779bba1 | ||
|
|
1ae73dd6ae | ||
|
|
f48ab57782 | ||
|
|
8b6ebfb351 | ||
|
|
9c0788c3e0 | ||
|
|
f61258d0b4 | ||
|
|
289f62f115 | ||
|
|
c3a98d5a4f | ||
|
|
d8374e9caa | ||
|
|
0648f23e94 | ||
|
|
e37cb2d63f | ||
|
|
ee64238bdd | ||
|
|
d3130e111f | ||
|
|
93f4eee887 | ||
|
|
408ada9097 | ||
|
|
e14ebd9503 | ||
|
|
289b99c30e | ||
|
|
f85c36a17e | ||
|
|
4715df3258 | ||
|
|
b20be101cc | ||
|
|
d424987587 | ||
|
|
a0575430dd | ||
|
|
c1e6344b18 | ||
|
|
ed0198382f | ||
|
|
577fb88843 | ||
|
|
2b879221b2 | ||
|
|
22db2e99f0 | ||
|
|
ef4aa488c3 | ||
|
|
57775f49bc | ||
|
|
e8a12d9897 | ||
|
|
f3b8d5b868 | ||
|
|
246235b921 | ||
|
|
0ded41afee | ||
|
|
d32e106bf0 | ||
|
|
bbb3748d3c | ||
|
|
08dd992344 | ||
|
|
914244a1ee | ||
|
|
e5f089610c | ||
|
|
6e26841817 | ||
|
|
ab60c4a9dd | ||
|
|
7009cd89e0 | ||
|
|
b93af37ea9 | ||
|
|
76b6a85509 | ||
|
|
a1d4b4ee98 | ||
|
|
51bca7ce2f | ||
|
|
70147f908a | ||
|
|
c4bf4f001f | ||
|
|
7d71f21753 | ||
|
|
285c78a5e4 | ||
|
|
9a2ad16926 | ||
|
|
afec21eb3d | ||
|
|
651ee720c6 | ||
|
|
2e6c5e1fad | ||
|
|
87366ae7fc | ||
|
|
27aea0b277 | ||
|
|
d4edc9f20d | ||
|
|
6c7991be75 | ||
|
|
3f81352df5 | ||
|
|
9d0e26ae28 | ||
|
|
9218008530 | ||
|
|
f36c5b8938 | ||
|
|
67199fd2d6 | ||
|
|
18d17ec674 | ||
|
|
3981ee7ec1 | ||
|
|
25c4aed368 | ||
|
|
c5a6ef673c | ||
|
|
79ba15fe9a | ||
|
|
e192207f4e | ||
|
|
baf1ecb436 | ||
|
|
ec67736dff | ||
|
|
766303b332 | ||
|
|
74226fbdf8 | ||
|
|
dc5374e284 | ||
|
|
f6ecf57737 | ||
|
|
940953b043 | ||
|
|
fbc5887fa6 | ||
|
|
61ce849546 | ||
|
|
afddaed9fc | ||
|
|
12158d73fa | ||
|
|
5f3abbf00e | ||
|
|
a02c58e231 | ||
|
|
59ebfb9bd4 | ||
|
|
57ca1d54bb | ||
|
|
5fccd5fe58 | ||
|
|
4658b7a533 | ||
|
|
d0f33e7c8a | ||
|
|
55bb328d48 | ||
|
|
a8a6fce385 | ||
|
|
60677a2414 |
@@ -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:
|
||||
|
||||
7
.github/ISSUE_TEMPLATE/release.md
vendored
7
.github/ISSUE_TEMPLATE/release.md
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
228
app/assets/javascripts/admin/spree/base.js.erb
Normal file
228
app/assets/javascripts/admin/spree/base.js.erb
Normal 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");
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
27
app/assets/javascripts/admin/spree/progress.coffee
Normal file
27
app/assets/javascripts/admin/spree/progress.coffee
Normal 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()
|
||||
|
||||
8
app/assets/javascripts/admin/spree/spree-select2.js.erb
Normal file
8
app/assets/javascripts/admin/spree/spree-select2.js.erb
Normal file
@@ -0,0 +1,8 @@
|
||||
//= require select2
|
||||
jQuery(function($) {
|
||||
// Make select beautiful
|
||||
if (typeof $('select.select2').select2 === 'function' )
|
||||
$('select.select2').select2({
|
||||
allowClear: true
|
||||
});
|
||||
})
|
||||
@@ -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()
|
||||
127
app/assets/javascripts/admin/spree/taxons/taxonomy.js.coffee
Normal file
127
app/assets/javascripts/admin/spree/taxons/taxonomy.js.coffee
Normal 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()
|
||||
@@ -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();
|
||||
|
||||
@@ -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 '*';
|
||||
|
||||
33
app/assets/stylesheets/admin/components/actions.scss
Normal file
33
app/assets/stylesheets/admin/components/actions.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#admin-menu {
|
||||
li {
|
||||
a {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
a::before {
|
||||
font-weight: normal;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
158
app/assets/stylesheets/admin/components/date-picker.scss
Normal file
158
app/assets/stylesheets/admin/components/date-picker.scss
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
app/assets/stylesheets/admin/components/messages.scss
Normal file
45
app/assets/stylesheets/admin/components/messages.scss
Normal 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) }
|
||||
}
|
||||
162
app/assets/stylesheets/admin/components/navigation.scss
Normal file
162
app/assets/stylesheets/admin/components/navigation.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
38
app/assets/stylesheets/admin/components/progress.scss
Normal file
38
app/assets/stylesheets/admin/components/progress.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
28
app/assets/stylesheets/admin/components/sidebar.scss
Normal file
28
app/assets/stylesheets/admin/components/sidebar.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
app/assets/stylesheets/admin/components/states.scss
Normal file
36
app/assets/stylesheets/admin/components/states.scss
Normal 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 }
|
||||
}
|
||||
14
app/assets/stylesheets/admin/components/table-filter.scss
Normal file
14
app/assets/stylesheets/admin/components/table-filter.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
25
app/assets/stylesheets/admin/globals/functions.scss
Normal file
25
app/assets/stylesheets/admin/globals/functions.scss
Normal 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);
|
||||
}
|
||||
}
|
||||
135
app/assets/stylesheets/admin/plugins/jstree.scss
Normal file
135
app/assets/stylesheets/admin/plugins/jstree.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
193
app/assets/stylesheets/admin/plugins/select2.scss
Normal file
193
app/assets/stylesheets/admin/plugins/select2.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
270
app/assets/stylesheets/admin/shared/forms.scss
Normal file
270
app/assets/stylesheets/admin/shared/forms.scss
Normal 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;
|
||||
}
|
||||
25
app/assets/stylesheets/admin/shared/icons.scss
Normal file
25
app/assets/stylesheets/admin/shared/icons.scss
Normal 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 }
|
||||
92
app/assets/stylesheets/admin/shared/layout.scss
Normal file
92
app/assets/stylesheets/admin/shared/layout.scss
Normal 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;
|
||||
}
|
||||
208
app/assets/stylesheets/admin/shared/tables.scss
Normal file
208
app/assets/stylesheets/admin/shared/tables.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
134
app/assets/stylesheets/admin/shared/typography.scss
Normal file
134
app/assets/stylesheets/admin/shared/typography.scss
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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}."
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
150
app/controllers/spree/admin/orders_controller.rb
Normal file
150
app/controllers/spree/admin/orders_controller.rb
Normal 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
|
||||
@@ -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
|
||||
129
app/controllers/spree/admin/payments_controller.rb
Normal file
129
app/controllers/spree/admin/payments_controller.rb
Normal 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
|
||||
@@ -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
|
||||
43
app/controllers/spree/admin/search_controller.rb
Normal file
43
app/controllers/spree/admin/search_controller.rb
Normal 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
|
||||
@@ -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
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(' ').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
|
||||
11
app/helpers/spree/admin/payments_helper.rb
Normal file
11
app/helpers/spree/admin/payments_helper.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
37
app/services/order_cycle_warning.rb
Normal file
37
app/services/order_cycle_warning.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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')
|
||||
|
||||
72
app/views/spree/admin/shared/_address_form.html.erb
Normal file
72
app/views/spree/admin/shared/_address_form.html.erb
Normal 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 %>
|
||||
@@ -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>
|
||||
@@ -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'
|
||||
@@ -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>
|
||||
|
||||
7
app/views/spree/admin/shared/_update_order_state.js
Normal file
7
app/views/spree/admin/shared/_update_order_state.js
Normal 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 %>
|
||||
@@ -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"
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
%hr/
|
||||
%p
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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' } }
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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
|
||||
|
||||
31
spec/services/order_cycle_warning_spec.rb
Normal file
31
spec/services/order_cycle_warning_spec.rb
Normal 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
41
vendor/assets/javascripts/equalize.js
vendored
Normal 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
41
vendor/assets/javascripts/jquery.cookie.js
vendored
Executable 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;
|
||||
};
|
||||
141
vendor/assets/javascripts/jquery.horizontalNav.js
vendored
Executable file
141
vendor/assets/javascripts/jquery.horizontalNav.js
vendored
Executable 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);
|
||||
4540
vendor/assets/javascripts/jquery.jstree/jquery.jstree.js
vendored
Executable file
4540
vendor/assets/javascripts/jquery.jstree/jquery.jstree.js
vendored
Executable file
File diff suppressed because it is too large
Load Diff
BIN
vendor/assets/javascripts/jquery.jstree/themes/apple/bg.jpg
vendored
Executable file
BIN
vendor/assets/javascripts/jquery.jstree/themes/apple/bg.jpg
vendored
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 312 B |
BIN
vendor/assets/javascripts/jquery.jstree/themes/apple/d.png
vendored
Executable file
BIN
vendor/assets/javascripts/jquery.jstree/themes/apple/d.png
vendored
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
BIN
vendor/assets/javascripts/jquery.jstree/themes/apple/dot_for_ie.gif
vendored
Executable file
BIN
vendor/assets/javascripts/jquery.jstree/themes/apple/dot_for_ie.gif
vendored
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 43 B |
61
vendor/assets/javascripts/jquery.jstree/themes/apple/style.css
vendored
Executable file
61
vendor/assets/javascripts/jquery.jstree/themes/apple/style.css
vendored
Executable 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 */
|
||||
BIN
vendor/assets/javascripts/jquery.jstree/themes/apple/throbber.gif
vendored
Executable file
BIN
vendor/assets/javascripts/jquery.jstree/themes/apple/throbber.gif
vendored
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
11
vendor/assets/javascripts/jquery.vAlign.js
vendored
Normal file
11
vendor/assets/javascripts/jquery.vAlign.js
vendored
Normal 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
319
vendor/assets/javascripts/spin.js
vendored
Normal 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)
|
||||
357
vendor/assets/stylesheets/jquery-ui.datepicker.css
vendored
Normal file
357
vendor/assets/stylesheets/jquery-ui.datepicker.css
vendored
Normal 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*/
|
||||
}
|
||||
Reference in New Issue
Block a user