diff --git a/public/css/grocy.css b/public/css/grocy.css
index f0eee717..0e0acff4 100644
--- a/public/css/grocy.css
+++ b/public/css/grocy.css
@@ -67,6 +67,15 @@ a.discrete-link:focus {
color: inherit;
}
+/* Hide the default up/down arrow buttons for number inputs because we use our own buttons in numberpicker */
+input[type='number'] {
+ -moz-appearance: textfield;
+}
+input::-webkit-outer-spin-button,
+input::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+}
+
/* Navigation style customizations */
#mainNav {
background-color: #e5e5e5 !important;
diff --git a/public/viewjs/components/numberpicker.js b/public/viewjs/components/numberpicker.js
new file mode 100644
index 00000000..8db711d9
--- /dev/null
+++ b/public/viewjs/components/numberpicker.js
@@ -0,0 +1,13 @@
+$(".numberpicker-down-button").unbind('click').on("click", function ()
+{
+ var inputElement = $(this).parent().parent().find('input[type="number"]')[0];
+ inputElement.stepDown();
+ $(inputElement).trigger('change');
+});
+
+$(".numberpicker-up-button").unbind('click').on("click", function()
+{
+ var inputElement = $(this).parent().parent().find('input[type="number"]')[0];
+ inputElement.stepUp();
+ $(inputElement).trigger('change');
+});
diff --git a/views/batteryform.blade.php b/views/batteryform.blade.php
index 292144d8..cd14a4e4 100644
--- a/views/batteryform.blade.php
+++ b/views/batteryform.blade.php
@@ -37,11 +37,15 @@
-
+ @php if($mode == 'edit') { $value = $battery->charge_interval_days; } else { $value = 0; } @endphp
+ @include('components.numberpicker', array(
+ 'id' => 'charge_interval_days',
+ 'label' => 'Charge cycle interval (days)',
+ 'value' => $value,
+ 'min' => '0',
+ 'hint' => $L('0 means suggestions for the next charge cycle are disabled'),
+ 'invalidFeedback' => $L('This cannot be negative')
+ ))
{{ $L('Save') }}
diff --git a/views/components/numberpicker.blade.php b/views/components/numberpicker.blade.php
new file mode 100644
index 00000000..0d205b3c
--- /dev/null
+++ b/views/components/numberpicker.blade.php
@@ -0,0 +1,27 @@
+@push('componentScripts')
+
+@endpush
+
+@php if(!isset($value)) { $value = 1; } @endphp
+@php if(empty($min)) { $min = 0; } @endphp
+@php if(empty($max)) { $max = 999999; } @endphp
+@php if(empty($step)) { $step = 1; } @endphp
+@php if(empty($hint)) { $hint = ''; } @endphp
+@php if(empty($hintId)) { $hintId = ''; } @endphp
+@php if(empty($additionalCssClasses)) { $additionalCssClasses = ''; } @endphp
+@php if(empty($additionalGroupCssClasses)) { $additionalGroupCssClasses = ''; } @endphp
+@php if(empty($additionalAttributes)) { $additionalAttributes = ''; } @endphp
+
+
diff --git a/views/components/productcard.blade.php b/views/components/productcard.blade.php
index db23546e..8b6eeb20 100644
--- a/views/components/productcard.blade.php
+++ b/views/components/productcard.blade.php
@@ -1,5 +1,5 @@
@push('componentScripts')
-
+
@endpush
diff --git a/views/consume.blade.php b/views/consume.blade.php
index 48c7acf8..48d343ff 100644
--- a/views/consume.blade.php
+++ b/views/consume.blade.php
@@ -17,11 +17,14 @@
'disallowAddProductWorkflows' => true
))
-
+ @include('components.numberpicker', array(
+ 'id' => 'amount',
+ 'label' => 'Amount',
+ 'hintId' => 'amount_qu_unit',
+ 'min' => 1,
+ 'value' => 1,
+ 'invalidFeedback' => $L('The amount cannot be lower than #1', '1')
+ ))
diff --git a/views/habitform.blade.php b/views/habitform.blade.php
index 09e99329..2865654a 100644
--- a/views/habitform.blade.php
+++ b/views/habitform.blade.php
@@ -42,11 +42,15 @@
{{ $L('A period type is required') }}
-
+ @php if($mode == 'edit') { $value = $habit->period_days; } else { $value = 0; } @endphp
+ @include('components.numberpicker', array(
+ 'id' => 'period_days',
+ 'label' => 'Period days',
+ 'value' => $value,
+ 'min' => '0',
+ 'additionalCssClasses' => 'input-group-habit-period-type',
+ 'invalidFeedback' => $L('This cannot be negative')
+ ))
diff --git a/views/inventory.blade.php b/views/inventory.blade.php
index 7186548a..eb547b3a 100644
--- a/views/inventory.blade.php
+++ b/views/inventory.blade.php
@@ -16,12 +16,16 @@
'nextInputSelector' => '#new_amount'
))
-
+ @include('components.numberpicker', array(
+ 'id' => 'new_amount',
+ 'label' => 'New amount',
+ 'hintId' => 'new_amount_qu_unit',
+ 'min' => 0,
+ 'value' => 1,
+ 'invalidFeedback' => $L('The amount cannot be lower than #1', '1'),
+ 'additionalAttributes' => ' data-notequal="notequal" not-equal="-1"'
+ ))
+
@include('components.datetimepicker', array(
'id' => 'best_before_date',
diff --git a/views/productform.blade.php b/views/productform.blade.php
index 5862f7e4..e6ba7c70 100644
--- a/views/productform.blade.php
+++ b/views/productform.blade.php
@@ -48,17 +48,24 @@
{{ $L('A location is required') }}
-
+ @php if($mode == 'edit') { $value = $product->min_stock_amount; } else { $value = 0; } @endphp
+ @include('components.numberpicker', array(
+ 'id' => 'min_stock_amount',
+ 'label' => 'Minimum stock amount',
+ 'min' => 0,
+ 'value' => $value,
+ 'invalidFeedback' => $L('The amount cannot be lower than #1', '0')
+ ))
-
+ @php if($mode == 'edit') { $value = $product->default_best_before_days; } else { $value = 0; } @endphp
+ @include('components.numberpicker', array(
+ 'id' => 'default_best_before_days',
+ 'label' => 'Default best before days',
+ 'min' => -1,
+ 'value' => $value,
+ 'invalidFeedback' => $L('The amount cannot be lower than #1', '-1'),
+ 'hint' => $L('For purchases this amount of days will be added to today for the best before date suggestion') . ' (' . $L('-1 means that this product never expires') . ')'
+ ))
-
+ @php if($mode == 'edit') { $value = $product->qu_factor_purchase_to_stock; } else { $value = 1; } @endphp
+ @include('components.numberpicker', array(
+ 'id' => 'qu_factor_purchase_to_stock',
+ 'label' => 'Factor purchase to stock quantity unit',
+ 'min' => 1,
+ 'value' => $value,
+ 'invalidFeedback' => $L('The amount cannot be lower than #1', '1'),
+ 'additionalCssClasses' => 'input-group-qu'
+ ))
diff --git a/views/purchase.blade.php b/views/purchase.blade.php
index ccadb41c..a55462da 100644
--- a/views/purchase.blade.php
+++ b/views/purchase.blade.php
@@ -30,17 +30,23 @@
'shortcutLabel' => 'Never expires'
))
-
+ @include('components.numberpicker', array(
+ 'id' => 'amount',
+ 'label' => 'Amount',
+ 'hintId' => 'amount_qu_unit',
+ 'min' => 1,
+ 'invalidFeedback' => $L('The amount cannot be lower than #1', '1')
+ ))
-
+ @include('components.numberpicker', array(
+ 'id' => 'price',
+ 'label' => 'Price',
+ 'min' => 0,
+ 'step' => 0.01,
+ 'value' => '',
+ 'hint' => $L('in #1 per purchase quantity unit', GROCY_CURRENCY),
+ 'invalidFeedback' => $L('The price cannot be lower than #1', '0')
+ ))
{{ $L('OK') }}
diff --git a/views/recipeposform.blade.php b/views/recipeposform.blade.php
index cfe60726..b4b3b8d9 100644
--- a/views/recipeposform.blade.php
+++ b/views/recipeposform.blade.php
@@ -35,11 +35,17 @@