Added localization support

This commit is contained in:
Bernd Bestel 2018-04-16 19:11:32 +02:00
parent 4949913ccb
commit 4656a85732
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
64 changed files with 1112 additions and 878 deletions

View File

@ -1,4 +1,7 @@
<?php
define('MODE', 'production'); # Either "production" or "dev"
define('CULTURE', 'en');
define('HTTP_USER', 'admin');
define('HTTP_PASSWORD', 'admin');

View File

@ -4,6 +4,7 @@ namespace Grocy\Controllers;
use \Grocy\Services\DatabaseService;
use \Grocy\Services\ApplicationService;
use \Grocy\Services\LocalizationService;
class BaseController
{
@ -15,6 +16,13 @@ class BaseController
$applicationService = new ApplicationService();
$container->view->set('version', $applicationService->GetInstalledVersion());
$localizationService = new LocalizationService(CULTURE);
$container->view->set('localizationStrings', $localizationService->GetCurrentCultureLocalizations());
$container->view->set('L', function($text, ...$placeholderValues) use($localizationService)
{
return $localizationService->Localize($text, ...$placeholderValues);
});
}
protected $AppContainer;

135
localization/de.php Normal file
View File

@ -0,0 +1,135 @@
<?php
return array(
'Stock overview' => 'Bestand',
'#1 products with #2 units in stock' => '#1 Produkte (#2 Einheiten) vorrätig',
'#1 products expiring within the next #2 days' => '#1 Produkte laufen innerhalb der nächsten #2 Tage ab',
'#1 products are already expired' => '#1 Produkte sind bereits abgelaufen',
'#1 products are below defined min. stock amount' => '#1 Produkte sind unter Mindestbestand',
'Product' => 'Produkt',
'Amount' => 'Menge',
'Next best before date' => 'Nächstes MHD',
'Logout' => 'Abmelden',
'Habits overview' => 'Gewohnheiten',
'Batteries overview' => 'Batterien',
'Purchase' => 'Einkauf',
'Consume' => 'Verbrauch',
'Inventory' => 'Inventur',
'Shopping list' => 'Einkaufszettel',
'Habit tracking' => 'Gewohnheit-Ausführung',
'Battery tracking' => 'Batterie-Ladzyklus',
'Products' => 'Produkte',
'Locations' => 'Standorte',
'Quantity units' => 'Mengeneinheiten',
'Habits' => 'Gewohnheiten',
'Batteries' => 'Batterien',
'Habit' => 'Gewohnheit',
'Next estimated tracking' => 'Nächste geplante Ausführung',
'Last tracked' => 'Zuletzt ausgeführt',
'Battery' => 'Batterie',
'Last charged' => 'Zuletzt geladen',
'Next planned charge cycle' => 'Nächster geplanter Ladezyklus',
'Best before' => 'MHD',
'OK' => 'OK',
'Product overview' => 'Produktübersicht',
'Stock quantity unit' => 'Mengeneinheit Bestand',
'Stock amount' => 'Bestand',
'Last purchased' => 'Zuletzt gekauft',
'Last used' => 'Zuletzt benutzt',
'Spoiled' => 'Verdorben',
'Barcode lookup is disabled' => 'Barcode-Suche ist deaktiviert',
'will be added to the list of barcodes for the selected product on submit' => 'wird der Liste der Barcodes für das ausgewählte Produkt beim Speichern hinzugefügt',
'New amount' => 'Neue Menge',
'Note' => 'Notiz',
'Tracked time' => 'Ausführungszeit',
'Habit overview' => 'Gewohnheit Übersicht',
'Tracked count' => 'Ausführungsanzahl',
'Battery overview' => 'Batterie Übersicht',
'Charge cycles count' => 'Ladezyklen',
'Create shopping list item' => 'Einkaufszettel Eintrag erstellen',
'Edit shopping list item' => 'Einkaufszettel Eintrag bearbeiten',
'#1 units were automatically added and will apply in addition to the amount entered here' => '#1 Einheiten wurden automatisch hinzugefügt und gelten zusätzlich der hier eingegebenen Menge',
'Save' => 'Speichern',
'Add' => 'Hinzufügen',
'Name' => 'Name',
'Location' => 'Standort',
'Min. stock amount' => 'Mindestbestand',
'QU purchase' => 'ME Einkauf',
'QU stock' => 'ME Bestand',
'QU factor' => 'ME-Faktor',
'Description' => 'Beschreibung',
'Create product' => 'Produkt erstellen',
'Barcode(s)' => 'Barcode(s)',
'Minimum stock amount' => 'Mindestbestand',
'Default best before days' => 'Standard Haltbarkeit in Tagen',
'Quantity unit purchase' => 'Mengeneinheit Einkauf',
'Quantity unit stock' => 'Mengeneinheit Bestand',
'Factor purchase to stock quantity unit' => 'Faktor Mengeneinheit Einkauf zu Mengeneinheit Bestand',
'Create location' => 'Standort erstellen',
'Create quantity unit' => 'Mengeneinheit erstellen',
'Period type' => 'Periodentyp',
'Period days' => 'Tage/Periode',
'Create habit' => 'Gewohnheit erstellen',
'Used in' => 'Benutzt in',
'Create battery' => 'Batterie erstellen',
'Edit battery' => 'Batterie bearbeiten',
'Edit habit' => 'Gewohnheit bearbeiten',
'Edit quantity unit' => 'Mengeneinheit bearbeiten',
'Edit product' => 'Produkt bearbeiten',
'Edit location' => 'Standort bearbeiten',
'Record data' => 'Daten erfassen',
'Manage master data' => 'Stammdaten verwalten',
'This will apply to added products' => 'Dies gilt für hinzugefügte Produkte',
'never' => 'nie',
'Add products that are below defined min. stock amount' => 'Produkte unter Mindestbestand hinzufügen',
'For purchases this amount of days will be added to today for the best before date suggestion' => 'Bei Einkäufen wird hierauf basierend das MHD vorausgefüllt',
'This means 1 #1 purchased will be converted into #2 #3 in stock' => 'Das bedeutet 1 #1 im Einkauf entsprechen #2 #3 im Bestand',
'Login' => 'Anmelden',
'Username' => 'Benutzername',
'Password' => 'Passwort',
'Invalid credentials, please try again' => 'Ungültige Zugangsdaten, bitte versuche es erneut',
//Constants
'manually' => 'Manuell',
'dynamic-regular' => 'Dynamisch regelmäßig',
//Technical component translations
'timeago_locale' => 'de',
'timeago_nan' => 'vor NaN Jahren',
'moment_locale' => 'de',
'bootstrap_datepicker_locale' => 'de',
'datatables_localization' => '{"sEmptyTable":"Keine Daten in der Tabelle vorhanden","sInfo":"_START_ bis _END_ von _TOTAL_ Einträgen","sInfoEmpty":"Keine Daten vorhanden","sInfoFiltered":"(gefiltert von _MAX_ Einträgen)","sInfoPostFix":"","sInfoThousands":".","sLengthMenu":"_MENU_ Einträge anzeigen","sLoadingRecords":"Wird geladen ..","sProcessing":"Bitte warten ..","sSearch":"Suchen","sZeroRecords":"Keine Einträge vorhanden","oPaginate":{"sFirst":"Erste","sPrevious":"Zurück","sNext":"Nächste","sLast":"Letzte"},"oAria":{"sSortAscending":": aktivieren, um Spalte aufsteigend zu sortieren","sSortDescending":": aktivieren, um Spalte absteigend zu sortieren"},"select":{"rows":{"0":"Zum Auswählen auf eine Zeile klicken","1":"1 Zeile ausgewählt","_":"%d Zeilen ausgewählt"}},"buttons":{"print":"Drucken","colvis":"Spalten","copy":"Kopieren","copyTitle":"In Zwischenablage kopieren","copyKeys":"Taste <i>ctrl</i> oder <i>⌘</i> + <i>C</i> um Tabelle<br>in Zwischenspeicher zu kopieren.<br><br>Um abzubrechen die Nachricht anklicken oder Escape drücken.","copySuccess":{"1":"1 Spalte kopiert","_":"%d Spalten kopiert"}}}',
//Demo data
'Cookies' => 'Cookies',
'Chocolate' => 'Schokolade',
'Pantry' => 'Vorratskammer',
'Candy cupboard' => 'Süßigkeitenschrank',
'Tinned food cupboard' => 'Konservenschrank',
'Fridge' => 'Kühlschrank',
'Piece' => 'Stück',
'Pack' => 'Packung',
'Glass' => 'Glas',
'Tin' => 'Dose',
'Can' => 'Becher',
'Bunch' => 'Bund',
'Gummy bears' => 'Gummibärchen',
'Crisps' => 'Chips',
'Eggs' => 'Eier',
'Noodles' => 'Nudeln',
'Pickles' => 'Essiggurken',
'Gulash soup' => 'Gulaschsuppe',
'Yogurt' => 'Joghurt',
'Cheese' => 'Käse',
'Cold cuts' => 'Aufschnitt',
'Paprika' => 'Paprika',
'Cucumber' => 'Gurke',
'Radish' => 'Radieschen',
'Tomato' => 'Tomaten',
'Changed towels in the bathroom' => 'Handtücher im Bad gewechselt',
'Cleaned the kitchen floor' => 'Küchenboden gewischt',
'Warranty ends' => 'Garantie endet',
'TV remote control' => 'TV Fernbedienung',
'Alarm clock' => 'Wecker',
'Heat remote control' => 'Fernbedienung Heizung'
);

14
localization/en.php Normal file
View File

@ -0,0 +1,14 @@
<?php
return array(
//Constants
'manually' => 'Manually',
'dynamic-regular' => 'Dynamic regular',
//Technical component translations
'timeago_locale' => 'en',
'timeago_nan' => 'NaN years ago',
'moment_locale' => '',
'bootstrap_datepicker_locale' => '',
'datatables_localization' => '{"sEmptyTable":"No data available in table","sInfo":"Showing _START_ to _END_ of _TOTAL_ entries","sInfoEmpty":"Showing 0 to 0 of 0 entries","sInfoFiltered":"(filtered from _MAX_ total entries)","sInfoPostFix":"","sInfoThousands":",","sLengthMenu":"Show _MENU_ entries","sLoadingRecords":"Loading...","sProcessing":"Processing...","sSearch":"Search:","sZeroRecords":"No matching records found","oPaginate":{"sFirst":"First","sLast":"Last","sNext":"Next","sPrevious":"Previous"},"oAria":{"sSortAscending":": activate to sort column ascending","sSortDescending":": activate to sort column descending"}}'
);

11
migrations/0021.sql Normal file
View File

@ -0,0 +1,11 @@
DELETE FROM locations
WHERE name = 'DefaultLocation';
DELETE FROM quantity_units
WHERE name = 'DefaultQuantityUnit';
DELETE FROM products
WHERE name = 'DefaultProduct1';
DELETE FROM products
WHERE name = 'DefaultProduct2';

View File

@ -46,12 +46,12 @@
}
.nav-sidebar > li > a:hover {
box-shadow: inset 4px 0 0 #337ab7;
box-shadow: inset 5px 0 0 #337ab7;
transition: all 0.3s;
}
.nav-sidebar > li > a:focus {
box-shadow: inset 4px 0 0 #ab2230;
box-shadow: inset 5px 0 0 #ab2230;
transition: all 0.3s;
}
@ -59,7 +59,7 @@
.nav-sidebar > .active > a:hover,
.nav-sidebar > .active > a:focus {
background-color: #d6d6d6;
box-shadow: inset 4px 0 0 #ab2230;
box-shadow: inset 5px 0 0 #ab2230;
transition: all 0.3s;
}
@ -114,7 +114,9 @@ a.discrete-link:focus {
font-weight: bold;
letter-spacing: -5px;
font-size: 2.2em;
color: inherit !important;
color: #0b024c !important;
margin-left: 0 !important;
padding-left: 5px !important;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1,17 +1,27 @@
var Grocy = { };
Grocy.Components = { };
$(function()
L = function(text, ...placeholderValues)
{
if (!Grocy.ActiveNav.isEmpty())
var localizedText = Grocy.LocalizationStrings[text];
if (localizedText === undefined)
{
var menuItem = $('.nav').find("[data-nav-for-page='" + Grocy.ActiveNav + "']");
menuItem.addClass('active');
}
localizedText = text;
}
for (var i = 0; i < placeholderValues.length; i++)
{
localizedText = localizedText.replace('#' + (i + 1), placeholderValues[i]);
}
return localizedText;
}
$.timeago.settings.allowFuture = true;
$('time.timeago').timeago();
});
if (!Grocy.ActiveNav.isEmpty())
{
var menuItem = $('.nav').find("[data-nav-for-page='" + Grocy.ActiveNav + "']");
menuItem.addClass('active');
}
$.timeago.settings.allowFuture = true;
$('time.timeago').timeago();
Grocy.FetchJson = function(url, success, error)
{

View File

@ -31,13 +31,11 @@
});
});
$(function()
{
$('#batteries-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
]
});
$('#batteries-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
],
'language': JSON.parse(L('datatables_localization'))
});

View File

@ -1,7 +1,5 @@
$(function()
{
$('#batteries-overview-table').DataTable({
'pageLength': 50,
'order': [[1, 'desc']]
});
$('#batteries-overview-table').DataTable({
'pageLength': 50,
'order': [[1, 'desc']],
'language': JSON.parse(L('datatables_localization'))
});

View File

@ -30,9 +30,6 @@
}
});
$(function()
{
$('#name').focus();
$('#battery-form').validator();
$('#battery-form').validator('validate');
});
$('#name').focus();
$('#battery-form').validator();
$('#battery-form').validator('validate');

View File

@ -44,50 +44,47 @@ $('#battery_id').on('change', function(e)
}
});
$(function()
$('.datetimepicker').datetimepicker(
{
$('.datetimepicker').datetimepicker(
{
format: 'YYYY-MM-DD HH:mm:ss',
showTodayButton: true,
calendarWeeks: true,
maxDate: moment()
});
format: 'YYYY-MM-DD HH:mm:ss',
showTodayButton: true,
calendarWeeks: true,
maxDate: moment()
});
$('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
$('#tracked_time').trigger('change');
$('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
$('#tracked_time').trigger('change');
$('#tracked_time').on('focus', function(e)
$('#tracked_time').on('focus', function(e)
{
if ($('#battery_id_text_input').val().length === 0)
{
if ($('#battery_id_text_input').val().length === 0)
$('#battery_id_text_input').focus();
}
});
$('.combobox').combobox({
appendId: '_text_input'
});
$('#battery_id').val('');
$('#battery_id_text_input').focus();
$('#battery_id_text_input').val('');
$('#battery_id_text_input').trigger('change');
$('#batterytracking-form').validator();
$('#batterytracking-form').validator('validate');
$('#batterytracking-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#batterytracking-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
$('#battery_id_text_input').focus();
event.preventDefault();
return false;
}
});
$('.combobox').combobox({
appendId: '_text_input'
});
$('#battery_id').val('');
$('#battery_id_text_input').focus();
$('#battery_id_text_input').val('');
$('#battery_id_text_input').trigger('change');
$('#batterytracking-form').validator();
$('#batterytracking-form').validator('validate');
$('#batterytracking-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#batterytracking-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});
}
});
$('#tracked_time').on('change', function(e)

View File

@ -6,11 +6,12 @@ Grocy.Components.BatteryCard.Refresh = function(batteryId)
function(batteryDetails)
{
$('#batterycard-battery-name').text(batteryDetails.battery.name);
$('#batterycard-battery-used_in').text(batteryDetails.battery.used_in);
$('#batterycard-battery-last-charged').text((batteryDetails.last_charged || 'never'));
$('#batterycard-battery-last-charged-timeago').text($.timeago(batteryDetails.last_charged || ''));
$('#batterycard-battery-charge-cycles-count').text((batteryDetails.charge_cycles_count || '0'));
EmptyElementWhenMatches('#batterycard-battery-last-charged-timeago', 'NaN years ago');
EmptyElementWhenMatches('#batterycard-battery-last-charged-timeago', L('timeago_nan'));
},
function(xhr)
{

View File

@ -9,11 +9,12 @@ $(function()
calendarWeeks: true,
orientation: 'bottom auto',
weekStart: 1,
showOnFocus: false
showOnFocus: false,
language: L('bootstrap_datepicker_locale')
});
$('.datepicker').trigger('change');
EmptyElementWhenMatches('#datepicker-timeago', 'NaN years ago');
EmptyElementWhenMatches('#datepicker-timeago', L('timeago_nan'));
});
$('.datepicker').on('keydown', function(e)
@ -82,7 +83,7 @@ $('.datepicker').on('change', function(e)
}
$('#datepicker-timeago').text($.timeago($('.datepicker').val()));
EmptyElementWhenMatches('#datepicker-timeago', 'NaN years ago');
EmptyElementWhenMatches('#datepicker-timeago', L('timeago_nan'));
});
$('#datepicker-button').on('click', function(e)

View File

@ -5,6 +5,7 @@ $(function()
format: 'YYYY-MM-DD HH:mm:ss',
showTodayButton: true,
calendarWeeks: true,
maxDate: moment()
maxDate: moment(),
locale: moment.locale('de')
});
});

View File

@ -10,7 +10,7 @@ Grocy.Components.HabitCard.Refresh = function (habitId)
$('#habitcard-habit-last-tracked-timeago').text($.timeago(habitDetails.last_tracked || ''));
$('#habitcard-habit-tracked-count').text((habitDetails.tracked_count || '0'));
EmptyElementWhenMatches('#habitcard-habit-last-tracked-timeago', 'NaN years ago');
EmptyElementWhenMatches('#habitcard-habit-last-tracked-timeago', L('timeago_nan'));
},
function(xhr)
{

View File

@ -9,13 +9,13 @@ Grocy.Components.ProductCard.Refresh = function(productId)
$('#productcard-product-stock-amount').text(productDetails.stock_amount || '0');
$('#productcard-product-stock-qu-name').text(productDetails.quantity_unit_stock.name);
$('#productcard-product-stock-qu-name2').text(productDetails.quantity_unit_stock.name);
$('#productcard-product-last-purchased').text((productDetails.last_purchased || 'never').substring(0, 10));
$('#productcard-product-last-purchased').text((productDetails.last_purchased || L('never')).substring(0, 10));
$('#productcard-product-last-purchased-timeago').text($.timeago(productDetails.last_purchased || ''));
$('#productcard-product-last-used').text((productDetails.last_used || 'never').substring(0, 10));
$('#productcard-product-last-used').text((productDetails.last_used || L('never')).substring(0, 10));
$('#productcard-product-last-used-timeago').text($.timeago(productDetails.last_used || ''));
EmptyElementWhenMatches('#productcard-product-last-purchased-timeago', 'NaN years ago');
EmptyElementWhenMatches('#productcard-product-last-used-timeago', 'NaN years ago');
EmptyElementWhenMatches('#productcard-product-last-purchased-timeago', L('timeago_nan'));
EmptyElementWhenMatches('#productcard-product-last-used-timeago', L('timeago_nan'));
},
function(xhr)
{

View File

@ -81,55 +81,52 @@ $('#product_id').on('change', function(e)
}
});
$(function()
{
$('.combobox').combobox({
appendId: '_text_input'
});
$('#product_id_text_input').on('change', function(e)
{
var input = $('#product_id_text_input').val().toString();
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
if (possibleOptionElement.length > 0)
{
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
}
});
$('#amount').val(1);
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#consume-form').validator();
$('#consume-form').validator('validate');
$('#amount').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
else
{
$(this).select();
}
});
$('#consume-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#consume-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});
$('.combobox').combobox({
appendId: '_text_input'
});
$('#product_id_text_input').on('change', function(e)
{
var input = $('#product_id_text_input').val().toString();
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
if (possibleOptionElement.length > 0)
{
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
}
});
$('#amount').val(1);
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#consume-form').validator();
$('#consume-form').validator('validate');
$('#amount').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
else
{
$(this).select();
}
});
$('#consume-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#consume-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});

View File

@ -30,12 +30,9 @@
}
});
$(function()
{
$('#name').focus();
$('#habit-form').validator();
$('#habit-form').validator('validate');
});
$('#name').focus();
$('#habit-form').validator();
$('#habit-form').validator('validate');
$('.input-group-habit-period-type').on('change', function(e)
{

View File

@ -31,13 +31,11 @@
});
});
$(function()
{
$('#habits-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
]
});
$('#habits-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
],
'language': JSON.parse(L('datatables_localization'))
});

View File

@ -1,7 +1,5 @@
$(function()
{
$('#habits-overview-table').DataTable({
'pageLength': 50,
'order': [[1, 'desc']]
});
$('#habits-overview-table').DataTable({
'pageLength': 50,
'order': [[1, 'desc']],
'language': JSON.parse(L('datatables_localization'))
});

View File

@ -44,42 +44,39 @@ $('#habit_id').on('change', function(e)
}
});
$(function()
$('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
$('#tracked_time').trigger('change');
$('#tracked_time').on('focus', function(e)
{
$('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
$('#tracked_time').trigger('change');
$('#tracked_time').on('focus', function(e)
if ($('#habit_id_text_input').val().length === 0)
{
if ($('#habit_id_text_input').val().length === 0)
{
$('#habit_id_text_input').focus();
}
});
$('#habit_id_text_input').focus();
}
});
$('.combobox').combobox({
appendId: '_text_input'
});
$('.combobox').combobox({
appendId: '_text_input'
});
$('#habit_id').val('');
$('#habit_id_text_input').focus();
$('#habit_id_text_input').val('');
$('#habit_id_text_input').trigger('change');
$('#habit_id').val('');
$('#habit_id_text_input').focus();
$('#habit_id_text_input').val('');
$('#habit_id_text_input').trigger('change');
$('#habittracking-form').validator();
$('#habittracking-form').validator('validate');
$('#habittracking-form').validator();
$('#habittracking-form').validator('validate');
$('#habittracking-form input').keydown(function(event)
$('#habittracking-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if (event.keyCode === 13) //Enter
if ($('#habittracking-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
if ($('#habittracking-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
event.preventDefault();
return false;
}
});
}
});
$('#tracked_time').on('keypress', function(e)

View File

@ -87,169 +87,166 @@ $('#product_id').on('change', function(e)
}
});
$(function()
{
$('.combobox').combobox({
appendId: '_text_input'
});
$('.combobox').combobox({
appendId: '_text_input'
});
$('#product_id_text_input').on('change', function(e)
$('#product_id_text_input').on('change', function(e)
{
var input = $('#product_id_text_input').val().toString();
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
if (GetUriParam('addbarcodetoselection') === undefined && possibleOptionElement.length > 0)
{
var input = $('#product_id_text_input').val().toString();
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
if (GetUriParam('addbarcodetoselection') === undefined && possibleOptionElement.length > 0)
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
}
else
{
var optionElement = $("#product_id option:contains('" + input + "')").first();
if (input.length > 0 && optionElement.length === 0 && GetUriParam('addbarcodetoselection') === undefined )
{
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
}
else
{
var optionElement = $("#product_id option:contains('" + input + "')").first();
if (input.length > 0 && optionElement.length === 0 && GetUriParam('addbarcodetoselection') === undefined )
{
bootbox.dialog({
message: '<strong>' + input + '</strong> could not be resolved to a product, how do you want to proceed?',
title: 'Create or assign product',
onEscape: function() { },
size: 'large',
backdrop: true,
buttons: {
cancel: {
label: 'Cancel',
className: 'btn-default',
callback: function() { }
},
addnewproduct: {
label: 'Add as new <u><strong>p</strong></u>roduct',
className: 'btn-success add-new-product-dialog-button',
callback: function()
{
window.location.href = '/product/new?prefillname=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
},
addbarcode: {
label: 'Add as <u><strong>b</strong></u>arcode to existing product',
className: 'btn-info add-new-barcode-dialog-button',
callback: function()
{
window.location.href = '/inventory?addbarcodetoselection=' + encodeURIComponent(input);
}
},
addnewproductwithbarcode: {
label: '<u><strong>A</strong></u>dd as new product + prefill barcode',
className: 'btn-warning add-new-product-with-barcode-dialog-button',
callback: function()
{
window.location.href = '/product/new?prefillbarcode=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
bootbox.dialog({
message: '<strong>' + input + '</strong> could not be resolved to a product, how do you want to proceed?',
title: 'Create or assign product',
onEscape: function() { },
size: 'large',
backdrop: true,
buttons: {
cancel: {
label: 'Cancel',
className: 'btn-default',
callback: function() { }
},
addnewproduct: {
label: 'Add as new <u><strong>p</strong></u>roduct',
className: 'btn-success add-new-product-dialog-button',
callback: function()
{
window.location.href = '/product/new?prefillname=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
},
addbarcode: {
label: 'Add as <u><strong>b</strong></u>arcode to existing product',
className: 'btn-info add-new-barcode-dialog-button',
callback: function()
{
window.location.href = '/inventory?addbarcodetoselection=' + encodeURIComponent(input);
}
},
addnewproductwithbarcode: {
label: '<u><strong>A</strong></u>dd as new product + prefill barcode',
className: 'btn-warning add-new-product-with-barcode-dialog-button',
callback: function()
{
window.location.href = '/product/new?prefillbarcode=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
}
}).on('keypress', function(e)
{
if (e.key === 'B' || e.key === 'b')
{
$('.add-new-barcode-dialog-button').click();
}
if (e.key === 'p' || e.key === 'P')
{
$('.add-new-product-dialog-button').click();
}
if (e.key === 'a' || e.key === 'A')
{
$('.add-new-product-with-barcode-dialog-button').click();
}
});
}
}
});
$('#new_amount').val('');
$('#best_before_date').val('');
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#inventory-form').validator({
custom: {
'isodate': function($el)
{
if ($el.val().length !== 0 && !moment($el.val(), 'YYYY-MM-DD', true).isValid())
{
return 'Wrong date format, needs to be YYYY-MM-DD';
}
else if (moment($el.val()).isValid())
{
if (moment($el.val()).isBefore(moment(), 'day'))
{
return 'This value cannot be before today.';
}
}
},
'notequal': function($el)
}).on('keypress', function(e)
{
if ($el.val().length !== 0 && $el.val().toString() === $el.attr('not-equal').toString())
if (e.key === 'B' || e.key === 'b')
{
return 'This value cannot be equal to ' + $el.attr('not-equal').toString();
$('.add-new-barcode-dialog-button').click();
}
}
if (e.key === 'p' || e.key === 'P')
{
$('.add-new-product-dialog-button').click();
}
if (e.key === 'a' || e.key === 'A')
{
$('.add-new-product-with-barcode-dialog-button').click();
}
});
}
});
$('#inventory-form').validator('validate');
$('#new_amount').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
else
{
$(this).select();
}
});
$('#inventory-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#inventory-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});
var prefillProduct = GetUriParam('createdproduct');
if (prefillProduct !== undefined)
{
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + prefillProduct + "']").first();
if (possibleOptionElement.length === 0)
{
possibleOptionElement = $("#product_id option:contains('" + prefillProduct + "')").first();
}
if (possibleOptionElement.length > 0)
{
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
$('#new_amount').focus();
}
}
var addBarcode = GetUriParam('addbarcodetoselection');
if (addBarcode !== undefined)
{
$('#addbarcodetoselection').text(addBarcode);
$('#flow-info-addbarcodetoselection').removeClass('hide');
$('#barcode-lookup-disabled-hint').removeClass('hide');
}
});
$('#new_amount').val('');
$('#best_before_date').val('');
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#inventory-form').validator({
custom: {
'isodate': function($el)
{
if ($el.val().length !== 0 && !moment($el.val(), 'YYYY-MM-DD', true).isValid())
{
return 'Wrong date format, needs to be YYYY-MM-DD';
}
else if (moment($el.val()).isValid())
{
if (moment($el.val()).isBefore(moment(), 'day'))
{
return 'This value cannot be before today.';
}
}
},
'notequal': function($el)
{
if ($el.val().length !== 0 && $el.val().toString() === $el.attr('not-equal').toString())
{
return 'This value cannot be equal to ' + $el.attr('not-equal').toString();
}
}
}
});
$('#inventory-form').validator('validate');
$('#new_amount').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
else
{
$(this).select();
}
});
$('#inventory-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#inventory-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});
var prefillProduct = GetUriParam('createdproduct');
if (prefillProduct !== undefined)
{
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + prefillProduct + "']").first();
if (possibleOptionElement.length === 0)
{
possibleOptionElement = $("#product_id option:contains('" + prefillProduct + "')").first();
}
if (possibleOptionElement.length > 0)
{
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
$('#new_amount').focus();
}
}
var addBarcode = GetUriParam('addbarcodetoselection');
if (addBarcode !== undefined)
{
$('#addbarcodetoselection').text(addBarcode);
$('#flow-info-addbarcodetoselection').removeClass('hide');
$('#barcode-lookup-disabled-hint').removeClass('hide');
}
$('#new_amount').on('keypress', function(e)
{
$('#new_amount').trigger('change');

View File

@ -30,9 +30,6 @@
}
});
$(function()
{
$('#name').focus();
$('#location-form').validator();
$('#location-form').validator('validate');
});
$('#name').focus();
$('#location-form').validator();
$('#location-form').validator('validate');

View File

@ -31,13 +31,11 @@
});
});
$(function()
{
$('#locations-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
]
});
$('#locations-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
],
'language': JSON.parse(L('datatables_localization'))
});

View File

@ -1,12 +1,9 @@
$(function()
$('.logout-button').hide();
$('#username').focus();
if (GetUriParam('invalid') === 'true')
{
$('.logout-button').hide();
$('#username').focus();
if (GetUriParam('invalid') === 'true')
{
$('#login-error').text('Invalid credentials, please try again.');
$('#login-error').show();
}
});
$('#login-error').text(L('Invalid credentials, please try again'));
$('#login-error').show();
}

View File

@ -37,59 +37,51 @@
}
});
$(function()
{
$('#barcode-taginput').tagsManager({
'hiddenTagListName': 'barcode',
'tagsContainer': '#barcode-taginput-container'
});
if (Grocy.EditMode === 'edit')
{
Grocy.FetchJson('/api/get-object/products/' + Grocy.EditObjectId,
function (product)
{
if (product.barcode !== null && product.barcode.length > 0)
{
product.barcode.split(',').forEach(function(item)
{
$('#barcode-taginput').tagsManager('pushTag', item);
});
}
},
function(xhr)
{
console.error(xhr);
}
);
}
$('#qu_factor_purchase_to_stock').trigger('change');
$('#name').focus();
$('#product-form').validator();
$('#product-form').validator('validate');
var prefillName = GetUriParam('prefillname');
if (prefillName !== undefined)
{
$('#name').val(prefillName);
$('#name').focus();
}
var prefillBarcode = GetUriParam('prefillbarcode');
if (prefillBarcode !== undefined)
{
$('#barcode-taginput').tagsManager('pushTag', prefillBarcode);
$('#name').focus();
}
$('#barcode-taginput').tagsManager({
'hiddenTagListName': 'barcode',
'tagsContainer': '#barcode-taginput-container'
});
if (Grocy.EditMode === 'edit')
{
Grocy.FetchJson('/api/get-object/products/' + Grocy.EditObjectId,
function (product)
{
if (product.barcode !== null && product.barcode.length > 0)
{
product.barcode.split(',').forEach(function(item)
{
$('#barcode-taginput').tagsManager('pushTag', item);
});
}
},
function(xhr)
{
console.error(xhr);
}
);
}
var prefillName = GetUriParam('prefillname');
if (prefillName !== undefined)
{
$('#name').val(prefillName);
$('#name').focus();
}
var prefillBarcode = GetUriParam('prefillbarcode');
if (prefillBarcode !== undefined)
{
$('#barcode-taginput').tagsManager('pushTag', prefillBarcode);
$('#name').focus();
}
$('.input-group-qu').on('change', function(e)
{
var factor = $('#qu_factor_purchase_to_stock').val();
if (factor > 1)
{
$('#qu-conversion-info').text('This means 1 ' + $("#qu_id_purchase option:selected").text() + ' purchased will be converted into ' + (1 * factor).toString() + ' ' + $("#qu_id_stock option:selected").text() + ' in stock.');
$('#qu-conversion-info').text(L('This means 1 #1 purchased will be converted into #2 #3 in stock', $("#qu_id_purchase option:selected").text(), (1 * factor).toString(), $("#qu_id_stock option:selected").text()));
$('#qu-conversion-info').show();
}
else
@ -97,3 +89,8 @@ $('.input-group-qu').on('change', function(e)
$('#qu-conversion-info').hide();
}
});
$('#name').focus();
$('#product-form').validator();
$('#product-form').validator('validate');
$('.input-group-qu').trigger('change');

View File

@ -31,13 +31,11 @@
});
});
$(function()
{
$('#products-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
]
});
$('#products-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
],
'language': JSON.parse(L('datatables_localization'))
});

View File

@ -96,170 +96,167 @@ $('#product_id').on('change', function(e)
}
});
$(function()
{
$('.combobox').combobox({
appendId: '_text_input'
});
$('.combobox').combobox({
appendId: '_text_input'
});
$('#product_id_text_input').on('change', function(e)
$('#product_id_text_input').on('change', function(e)
{
var input = $('#product_id_text_input').val().toString();
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
if (GetUriParam('addbarcodetoselection') === undefined && possibleOptionElement.length > 0)
{
var input = $('#product_id_text_input').val().toString();
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
if (GetUriParam('addbarcodetoselection') === undefined && possibleOptionElement.length > 0)
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
}
else
{
var optionElement = $("#product_id option:contains('" + input + "')").first();
if (input.length > 0 && optionElement.length === 0 && GetUriParam('addbarcodetoselection') === undefined )
{
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
}
else
{
var optionElement = $("#product_id option:contains('" + input + "')").first();
if (input.length > 0 && optionElement.length === 0 && GetUriParam('addbarcodetoselection') === undefined )
{
bootbox.dialog({
message: '<strong>' + input + '</strong> could not be resolved to a product, how do you want to proceed?',
title: 'Create or assign product',
onEscape: function() { },
size: 'large',
backdrop: true,
buttons: {
cancel: {
label: 'Cancel',
className: 'btn-default',
callback: function() { }
},
addnewproduct: {
label: 'Add as new <u><strong>p</strong></u>roduct',
className: 'btn-success add-new-product-dialog-button',
callback: function()
{
window.location.href = '/product/new?prefillname=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
},
addbarcode: {
label: 'Add as <u><strong>b</strong></u>arcode to existing product',
className: 'btn-info add-new-barcode-dialog-button',
callback: function()
{
window.location.href = '/purchase?addbarcodetoselection=' + encodeURIComponent(input);
}
},
addnewproductwithbarcode: {
label: '<u><strong>A</strong></u>dd as new product + prefill barcode',
className: 'btn-warning add-new-product-with-barcode-dialog-button',
callback: function()
{
window.location.href = '/product/new?prefillbarcode=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
bootbox.dialog({
message: '<strong>' + input + '</strong> could not be resolved to a product, how do you want to proceed?',
title: 'Create or assign product',
onEscape: function() { },
size: 'large',
backdrop: true,
buttons: {
cancel: {
label: 'Cancel',
className: 'btn-default',
callback: function() { }
},
addnewproduct: {
label: 'Add as new <u><strong>p</strong></u>roduct',
className: 'btn-success add-new-product-dialog-button',
callback: function()
{
window.location.href = '/product/new?prefillname=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
},
addbarcode: {
label: 'Add as <u><strong>b</strong></u>arcode to existing product',
className: 'btn-info add-new-barcode-dialog-button',
callback: function()
{
window.location.href = '/purchase?addbarcodetoselection=' + encodeURIComponent(input);
}
},
addnewproductwithbarcode: {
label: '<u><strong>A</strong></u>dd as new product + prefill barcode',
className: 'btn-warning add-new-product-with-barcode-dialog-button',
callback: function()
{
window.location.href = '/product/new?prefillbarcode=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
}
}).on('keypress', function(e)
{
if (e.key === 'B' || e.key === 'b')
{
$('.add-new-barcode-dialog-button').click();
}
if (e.key === 'p' || e.key === 'P')
{
$('.add-new-product-dialog-button').click();
}
if (e.key === 'a' || e.key === 'A')
{
$('.add-new-product-with-barcode-dialog-button').click();
}
});
}
}
});
$('#amount').val(0);
$('#best_before_date').val('');
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#purchase-form').validator({
custom: {
'isodate': function($el)
{
if ($el.val().length !== 0 && !moment($el.val(), 'YYYY-MM-DD', true).isValid())
{
return 'Wrong date format, needs to be YYYY-MM-DD';
}
else if (moment($el.val()).isValid())
{
if (moment($el.val()).isBefore(moment(), 'day'))
{
return 'This value cannot be before today.';
}
}
}
}
});
$('#purchase-form').validator('validate');
$('#best_before_date').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
});
$('#amount').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
else
{
$(this).select();
}
});
$('#purchase-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#purchase-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
}).on('keypress', function(e)
{
event.preventDefault();
return false;
}
if (e.key === 'B' || e.key === 'b')
{
$('.add-new-barcode-dialog-button').click();
}
if (e.key === 'p' || e.key === 'P')
{
$('.add-new-product-dialog-button').click();
}
if (e.key === 'a' || e.key === 'A')
{
$('.add-new-product-with-barcode-dialog-button').click();
}
});
}
});
var prefillProduct = GetUriParam('createdproduct');
if (prefillProduct !== undefined)
{
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + prefillProduct + "']").first();
if (possibleOptionElement.length === 0)
{
possibleOptionElement = $("#product_id option:contains('" + prefillProduct + "')").first();
}
if (possibleOptionElement.length > 0)
{
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
$('#best_before_date').focus();
}
}
var addBarcode = GetUriParam('addbarcodetoselection');
if (addBarcode !== undefined)
{
$('#addbarcodetoselection').text(addBarcode);
$('#flow-info-addbarcodetoselection').removeClass('hide');
$('#barcode-lookup-disabled-hint').removeClass('hide');
}
});
$('#amount').val(0);
$('#best_before_date').val('');
$('#product_id').val('');
$('#product_id_text_input').focus();
$('#product_id_text_input').val('');
$('#product_id_text_input').trigger('change');
$('#purchase-form').validator({
custom: {
'isodate': function($el)
{
if ($el.val().length !== 0 && !moment($el.val(), 'YYYY-MM-DD', true).isValid())
{
return 'Wrong date format, needs to be YYYY-MM-DD';
}
else if (moment($el.val()).isValid())
{
if (moment($el.val()).isBefore(moment(), 'day'))
{
return 'This value cannot be before today.';
}
}
}
}
});
$('#purchase-form').validator('validate');
$('#best_before_date').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
});
$('#amount').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
else
{
$(this).select();
}
});
$('#purchase-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#purchase-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});
var prefillProduct = GetUriParam('createdproduct');
if (prefillProduct !== undefined)
{
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + prefillProduct + "']").first();
if (possibleOptionElement.length === 0)
{
possibleOptionElement = $("#product_id option:contains('" + prefillProduct + "')").first();
}
if (possibleOptionElement.length > 0)
{
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
$('#best_before_date').focus();
}
}
var addBarcode = GetUriParam('addbarcodetoselection');
if (addBarcode !== undefined)
{
$('#addbarcodetoselection').text(addBarcode);
$('#flow-info-addbarcodetoselection').removeClass('hide');
$('#barcode-lookup-disabled-hint').removeClass('hide');
}
$('#best_before_date').on('change', function(e)
{
$('#purchase-form').validator('validate');

View File

@ -30,9 +30,6 @@
}
});
$(function()
{
$('#name').focus();
$('#quantityunit-form').validator();
$('#quantityunit-form').validator('validate');
});
$('#name').focus();
$('#quantityunit-form').validator();
$('#quantityunit-form').validator('validate');

View File

@ -31,13 +31,11 @@
});
});
$(function()
{
$('#quantityunits-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
]
});
$('#quantityunits-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
],
'language': JSON.parse(L('datatables_localization'))
});

View File

@ -26,13 +26,11 @@ $(document).on('click', '#add-products-below-min-stock-amount', function(e)
);
});
$(function()
{
$('#shoppinglist-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
]
});
$('#shoppinglist-table').DataTable({
'pageLength': 50,
'order': [[1, 'asc']],
'columnDefs': [
{ 'orderable': false, 'targets': 0 }
],
'language': JSON.parse(L('datatables_localization'))
});

View File

@ -36,22 +36,13 @@ $('#product_id').on('change', function(e)
if (productId)
{
Grocy.Components.ProductCard.Refresh(productId);
Grocy.FetchJson('/api/stock/get-product-details/' + productId,
function (productDetails)
{
$('#selected-product-name').text(productDetails.product.name);
$('#selected-product-stock-amount').text(productDetails.stock_amount || '0');
$('#selected-product-stock-qu-name').text(productDetails.quantity_unit_stock.name);
$('#selected-product-stock-qu-name2').text(productDetails.quantity_unit_stock.name);
$('#selected-product-last-purchased').text((productDetails.last_purchased || 'never').substring(0, 10));
$('#selected-product-last-purchased-timeago').text($.timeago(productDetails.last_purchased || ''));
$('#selected-product-last-used').text((productDetails.last_used || 'never').substring(0, 10));
$('#selected-product-last-used-timeago').text($.timeago(productDetails.last_used || ''));
$('#amount_qu_unit').text(productDetails.quantity_unit_purchase.name);
EmptyElementWhenMatches('#selected-product-last-purchased-timeago', 'NaN years ago');
EmptyElementWhenMatches('#selected-product-last-used-timeago', 'NaN years ago');
if ($('#product_id').hasClass('suppress-next-custom-validate-event'))
{
$('#product_id').removeClass('suppress-next-custom-validate-event');
@ -97,53 +88,50 @@ $('#product_id').on('change', function(e)
}
});
$(function()
$('.combobox').combobox({
appendId: '_text_input'
});
$('#product_id_text_input').on('change', function(e)
{
$('.combobox').combobox({
appendId: '_text_input'
});
var input = $('#product_id_text_input').val().toString();
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
$('#product_id_text_input').on('change', function(e)
{
var input = $('#product_id_text_input').val().toString();
var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
if (possibleOptionElement.length > 0 && possibleOptionElement.text().length > 0) {
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
}
});
$('#product_id_text_input').focus();
$('#product_id_text_input').trigger('change');
if (Grocy.EditMode === 'edit')
{
$('#product_id').addClass('suppress-next-custom-validate-event');
if (possibleOptionElement.length > 0 && possibleOptionElement.text().length > 0) {
$('#product_id').val(possibleOptionElement.val());
$('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
}
$('#shoppinglist-form').validator();
$('#shoppinglist-form').validator('validate');
$('#amount').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
});
$('#shoppinglist-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#shoppinglist-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});
});
$('#product_id_text_input').focus();
$('#product_id_text_input').trigger('change');
if (Grocy.EditMode === 'edit')
{
$('#product_id').addClass('suppress-next-custom-validate-event');
$('#product_id').trigger('change');
}
$('#shoppinglist-form').validator();
$('#shoppinglist-form').validator('validate');
$('#amount').on('focus', function(e)
{
if ($('#product_id_text_input').val().length === 0)
{
$('#product_id_text_input').focus();
}
});
$('#shoppinglist-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
if ($('#shoppinglist-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
event.preventDefault();
return false;
}
}
});

View File

@ -1,7 +1,5 @@
$(function()
{
$('#stock-overview-table').DataTable({
'pageLength': 50,
'order': [[2, 'asc']]
});
$('#stock-overview-table').DataTable({
'pageLength': 50,
'order': [[2, 'asc']],
'language': JSON.parse(L('datatables_localization'))
});

View File

@ -2,47 +2,52 @@
namespace Grocy\Services;
use \Grocy\Services\LocalizationService;
class DemoDataGeneratorService extends BaseService
{
public function PopulateDemoData()
{
$localizationService = new LocalizationService(CULTURE);
$rowCount = $this->DatabaseService->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = -1')->fetchColumn();
if (intval($rowCount) === 0)
{
$sql = "
UPDATE locations SET name = 'Vorratskammer', description = '' WHERE id = 1;
INSERT INTO locations (name) VALUES ('Süßigkeitenschrank'); --2
INSERT INTO locations (name) VALUES ('Konservenschrank'); --3
INSERT INTO locations (name) VALUES ('Kühlschrank'); --4
INSERT INTO locations (name) VALUES ('{$localizationService->Localize('Pantry')}'); --2
INSERT INTO locations (name) VALUES ('{$localizationService->Localize('Candy cupboard')}'); --3
INSERT INTO locations (name) VALUES ('{$localizationService->Localize('Tinned food cupboard')}'); --4
INSERT INTO locations (name) VALUES ('{$localizationService->Localize('Fridge')}'); --5
UPDATE quantity_units SET name = 'Stück' WHERE id = 1;
INSERT INTO quantity_units (name) VALUES ('Packung'); --2
INSERT INTO quantity_units (name) VALUES ('Glas'); --3
INSERT INTO quantity_units (name) VALUES ('Dose'); --4
INSERT INTO quantity_units (name) VALUES ('Becher'); --5
INSERT INTO quantity_units (name) VALUES ('Bund'); --6
INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Piece')}'); --2
INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Pack')}'); --3
INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Glass')}'); --4
INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Tin')}'); --5
INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Can')}'); --6
INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Bunch')}'); --7
DELETE FROM products WHERE id IN (1, 2);
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('Gummibärchen', 2, 2, 2, 1, 8); --3
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('Chips', 2, 2, 2, 1, 10); --4
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Eier', 1, 2, 1, 10); --5
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Nudeln', 1, 2, 2, 1); --6
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Essiggurken', 3, 3, 3, 1); --7
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Gulaschsuppe', 3, 4, 4, 1); --8
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Joghurt', 4, 5, 5, 1); --9
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Käse', 4, 2, 2, 1); --10
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Aufschnitt', 4, 2, 2, 1); --11
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Paprika', 4, 1, 1, 1); --12
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Gurke', 4, 1, 1, 1); --13
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Radieschen', 4, 6, 6, 1); --14
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Tomate', 4, 1, 1, 1); --15
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('{$localizationService->Localize('Cookies')}', 3, 3, 3, 1, 8); --1
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('{$localizationService->Localize('Chocolate')}', 3, 3, 3, 1, 8); --2
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('{$localizationService->Localize('Gummy bears')}', 3, 3, 3, 1, 8); --3
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('{$localizationService->Localize('Crisps')}', 3, 3, 3, 1, 10); --4
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Eggs')}', 5, 3, 2, 10); --5
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Noodles')}', 3, 3, 3, 1); --6
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Pickles')}', 4,4, 4, 1); --7
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Gulash soup')}', 4, 5, 5, 1); --8
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Yogurt')}', 5, 6, 6, 1); --9
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Cheese')}', 5, 3, 3, 1); --10
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Cold cuts')}', 5, 3, 3, 1); --11
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Paprika')}', 5, 2, 2, 1); --12
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Cucumber')}', 5, 2, 2, 1); --13
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Radish')}', 5, 7, 7, 1); --14
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Tomato')}', 5, 2, 2, 1); --15
INSERT INTO habits (name, period_type, period_days) VALUES ('Changed towels in the bathroom', 'manually', 5); --1
INSERT INTO habits (name, period_type, period_days) VALUES ('Cleaned the kitchen floor', 'dynamic-regular', 7); --2
INSERT INTO habits (name, period_type, period_days) VALUES ('{$localizationService->Localize('Changed towels in the bathroom')}', 'manually', 5); --1
INSERT INTO habits (name, period_type, period_days) VALUES ('{$localizationService->Localize('Cleaned the kitchen floor')}', 'dynamic-regular', 7); --2
INSERT INTO batteries (name, description, used_in) VALUES ('Battery1', 'Warranty ends 2022', 'TV remote control'); --1
INSERT INTO batteries (name, description, used_in) VALUES ('Battery2', 'Warranty ends 2022', 'Alarm clock'); --2
INSERT INTO batteries (name, description, used_in, charge_interval_days) VALUES ('Battery3', 'Warranty ends 2022', 'Heat remote control', 60); --3
INSERT INTO batteries (name, description, used_in) VALUES ('{$localizationService->Localize('Battery')}1', '{$localizationService->Localize('Warranty ends')} 2023', '{$localizationService->Localize('TV remote control')}'); --1
INSERT INTO batteries (name, description, used_in) VALUES ('{$localizationService->Localize('Battery')}2', '{$localizationService->Localize('Warranty ends')} 2022', '{$localizationService->Localize('Alarm clock')}'); --2
INSERT INTO batteries (name, description, used_in, charge_interval_days) VALUES ('{$localizationService->Localize('Battery')}3', '{$localizationService->Localize('Warranty ends')} 2022', '{$localizationService->Localize('Heat remote control')}', 60); --3
INSERT INTO migrations (migration) VALUES (-1);
";

View File

@ -0,0 +1,103 @@
<?php
namespace Grocy\Services;
class LocalizationService extends BaseService
{
const DEFAULT_CULTURE = 'en';
public function __construct(string $culture)
{
parent::__construct();
$this->Culture = $culture;
$this->StringsDefaultCulture = $this->LoadLocalizationFile(self::DEFAULT_CULTURE);
$this->StringsCurrentCulture = $this->LoadLocalizationFile($culture);
$this->StringsMerged = array_merge($this->StringsDefaultCulture, $this->StringsCurrentCulture);
}
protected $Culture;
protected $StringsDefaultCulture;
protected $StringsCurrentCulture;
protected $StringsMerged;
private function LoadLocalizationFile(string $culture)
{
$file = __DIR__ . "/../localization/$culture.php";
if (file_exists($file))
{
return require $file;
}
else
{
return array();
}
}
private function LogMissingLocalization(string $culture, string $text)
{
$file = __DIR__ . "/../data/missing_translations_$culture.json";
$missingTranslations = array();
if (file_exists($file))
{
$missingTranslations = json_decode(file_get_contents($file), true);
}
if (!array_key_exists($text, $missingTranslations))
{
$missingTranslations[$text] = '#TranslationMissing#';
}
if (count($missingTranslations) > 0)
{
file_put_contents($file, json_encode($missingTranslations, JSON_PRETTY_PRINT));
}
}
public function Localize(string $text, ...$placeholderValues)
{
if (MODE === 'dev')
{
if (!array_key_exists($text, $this->StringsDefaultCulture))
{
$this->LogMissingLocalization(self::DEFAULT_CULTURE, $text);
}
if (!array_key_exists($text, $this->StringsCurrentCulture))
{
$this->LogMissingLocalization($this->Culture, $text);
}
}
$localizedText = $text;
if (array_key_exists($text, $this->StringsMerged))
{
$localizedText = $this->StringsMerged[$text];
}
for ($i = 0; $i < count($placeholderValues); $i++)
{
$localizedText = str_replace('#' . ($i + 1), $placeholderValues[$i], $localizedText);
}
return $localizedText;
}
public function GetLocalizations()
{
return $this->StringsMerged;
}
public function GetDefaultCultureLocalizations()
{
return $this->StringsDefaultCulture;
}
public function GetCurrentCultureLocalizations()
{
return $this->StringsCurrentCulture;
}
}

View File

@ -1 +1 @@
1.7.0
1.8.0

View File

@ -1,6 +1,6 @@
@extends('layout.default')
@section('title', 'Batteries')
@section('title', $L('Batteries'))
@section('activeNav', 'batteries')
@section('viewJsName', 'batteries')
@ -8,9 +8,9 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<h1 class="page-header">
Batteries
@yield('title')
<a class="btn btn-default" href="/battery/new" role="button">
<i class="fa fa-plus"></i>&nbsp;Add
<i class="fa fa-plus"></i>&nbsp;{{ $L('Add') }}
</a>
</h1>
@ -19,9 +19,9 @@
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Description</th>
<th>Used in</th>
<th>{{ $L('Name') }}</th>
<th>{{ $L('Description') }}</th>
<th>{{ $L('Used in') }}</th>
</tr>
</thead>
<tbody>

View File

@ -1,21 +1,21 @@
@extends('layout.default')
@section('title', 'Batteries overview')
@section('title', $L('Batteries overview'))
@section('activeNav', 'batteriesoverview')
@section('viewJsName', 'batteriesoverview')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<h1 class="page-header">Batteries overview</h1>
<h1 class="page-header">@yield('title')</h1>
<div class="table-responsive">
<table id="batteries-overview-table" class="table table-striped">
<thead>
<tr>
<th>Battery</th>
<th>Last charged</th>
<th>Next planned charge cycle</th>
<th>{{ $L('Battery') }}</th>
<th>{{ $L('Last charged') }}</th>
<th>{{ $L('Next planned charge cycle') }}</th>
</tr>
</thead>
<tbody>

View File

@ -1,9 +1,9 @@
@extends('layout.default')
@if($mode == 'edit')
@section('title', 'Edit battery')
@section('title', $L('Edit battery'))
@else
@section('title', 'Create battery')
@section('title', $L('Create battery'))
@endif
@section('viewJsName', 'batteryform')
@ -22,22 +22,22 @@
<form id="battery-form">
<div class="form-group">
<label for="name">Name</label>
<label for="name">{{ $L('Name') }}</label>
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $battery->name }}@endif">
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="description">Description</label>
<label for="description">{{ $L('Description') }}</label>
<input type="text" class="form-control" id="description" name="description" value="@if($mode == 'edit'){{ $battery->description }}@endif">
</div>
<div class="form-group">
<label for="name">Used in</label>
<label for="name">{{ $L('Used in') }}</label>
<input type="text" class="form-control" id="used_in" name="used_in" value="@if($mode == 'edit'){{ $battery->used_in }}@endif">
</div>
<button id="save-battery-button" type="submit" class="btn btn-default">Save</button>
<button id="save-battery-button" type="submit" class="btn btn-default">{{ $L('Save') }}</button>
</form>

View File

@ -1,18 +1,18 @@
@extends('layout.default')
@section('title', 'Battery tracking')
@section('title', $L('Battery tracking'))
@section('activeNav', 'batterytracking')
@section('viewJsName', 'batterytracking')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2">
<h1 class="page-header">Battery tracking</h1>
<h1 class="page-header">@yield('title')</h1>
<form id="batterytracking-form">
<div class="form-group">
<label for="battery_id">Battery</label>
<label for="battery_id">{{ $L('Battery') }}</label>
<select class="form-control combobox" id="battery_id" name="battery_id" required>
<option value=""></option>
@foreach($batteries as $battery)
@ -23,7 +23,7 @@
</div>
<div class="form-group">
<label for="tracked_time">Tracked time</label>
<label for="tracked_time">{{ $L('Tracked time') }}</label>
<div class="input-group date datetimepicker">
<input type="text" class="form-control" id="tracked_time" name="tracked_time" required >
<span class="input-group-addon">
@ -33,7 +33,7 @@
<div class="help-block with-errors"></div>
</div>
<button id="save-batterytracking-button" type="submit" class="btn btn-default">OK</button>
<button id="save-batterytracking-button" type="submit" class="btn btn-default">{{ $L('OK') }}</button>
</form>

View File

@ -4,11 +4,12 @@
<div class="main well">
<h3>Battery overview <strong><span id="batterycard-battery-name"></span></strong></h3>
<h3>{{ $L('Battery overview') }} <strong><span id="batterycard-battery-name"></span></strong></h3>
<p>
<strong>Charge cycles count:</strong> <span id="batterycard-battery-charge-cycles-count"></span><br>
<strong>Last charged:</strong> <span id="batterycard-battery-last-charged"></span> <time id="batterycard-battery-last-charged-timeago" class="timeago timeago-contextual"></time><br>
<strong>{{ $L('Used in') }}:</strong> <span id="batterycard-battery-used_in"></span><br>
<strong>{{ $L('Charge cycles count') }}:</strong> <span id="batterycard-battery-charge-cycles-count"></span><br>
<strong>{{ $L('Last charged') }}:</strong> <span id="batterycard-battery-last-charged"></span> <time id="batterycard-battery-last-charged-timeago" class="timeago timeago-contextual"></time><br>
</p>
</div>

View File

@ -3,7 +3,7 @@
@endpush
<div class="form-group">
<label for="{{ $id }}">{!! $label !!}&nbsp;&nbsp;<span class="small text-muted"><time id="datepicker-timeago" class="timeago timeago-contextual"></time></span></label>
<label for="{{ $id }}">{{ $L($label) }}&nbsp;&nbsp;<span class="small text-muted"><time id="datepicker-timeago" class="timeago timeago-contextual"></time>@if(!empty($hint))<br>{{ $L($hint) }}@endif</span></label>
<div class="input-group date">
<input type="text" data-isodate="isodate" class="form-control datepicker" id="{{ $id }}" name="{{ $id }}" required autocomplete="off">
<div id="datepicker-button" class="input-group-addon">

View File

@ -3,7 +3,7 @@
@endpush
<div class="form-group">
<label for="{{ $id }}">{{ $label }}</label>
<label for="{{ $id }}">{{ $L($label) }}</label>
<div class="input-group date datetimepicker">
<input type="text" class="form-control" id="{{ $id }}" name="{{ $id }}" required>
<span class="input-group-addon">

View File

@ -4,11 +4,11 @@
<div class="main well">
<h3>Habit overview <strong><span id="habitcard-habit-name"></span></strong></h3>
<h3>{{ $L('Habit overview') }} <strong><span id="habitcard-habit-name"></span></strong></h3>
<p>
<strong>Tracked count:</strong> <span id="habitcard-habit-tracked-count"></span><br>
<strong>Last tracked:</strong> <span id="habitcard-habit-last-tracked"></span> <time id="habitcard-habit-last-tracked-timeago" class="timeago timeago-contextual"></time><br>
<strong>{{ $L('Tracked count') }}:</strong> <span id="habitcard-habit-tracked-count"></span><br>
<strong>{{ $L('Last tracked') }}:</strong> <span id="habitcard-habit-last-tracked"></span> <time id="habitcard-habit-last-tracked-timeago" class="timeago timeago-contextual"></time><br>
</p>
</div>

View File

@ -4,13 +4,13 @@
<div class="main well">
<h3>Product overview <strong><span id="productcard-product-name"></span></strong></h3>
<h4><strong>Stock quantity unit:</strong> <span id="productcard-product-stock-qu-name"></span></h4>
<h3>{{ $L('Product overview') }} <strong><span id="productcard-product-name"></span></strong></h3>
<h4><strong>{{ $L('Stock quantity unit') }}:</strong> <span id="productcard-product-stock-qu-name"></span></h4>
<p>
<strong>Stock amount:</strong> <span id="productcard-product-stock-amount"></span> <span id="productcard-product-stock-qu-name2"></span><br>
<strong>Last purchased:</strong> <span id="productcard-product-last-purchased"></span> <time id="productcard-product-last-purchased-timeago" class="timeago timeago-contextual"></time><br>
<strong>Last used:</strong> <span id="productcard-product-last-used"></span> <time id="productcard-product-last-used-timeago" class="timeago timeago-contextual"></time>
<strong>{{ $L('Stock amount') }}:</strong> <span id="productcard-product-stock-amount"></span> <span id="productcard-product-stock-qu-name2"></span><br>
<strong>{{ $L('Last purchased') }}:</strong> <span id="productcard-product-last-purchased"></span> <time id="productcard-product-last-purchased-timeago" class="timeago timeago-contextual"></time><br>
<strong>{{ $L('Last used') }}:</strong> <span id="productcard-product-last-used"></span> <time id="productcard-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p>
</div>

View File

@ -1,18 +1,18 @@
@extends('layout.default')
@section('title', 'Consume')
@section('title', $L('Consume'))
@section('activeNav', 'consume')
@section('viewJsName', 'consume')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2">
<h1 class="page-header">Consume</h1>
<h1 class="page-header">@yield('title')</h1>
<form id="consume-form">
<div class="form-group">
<label for="product_id">Product&nbsp;&nbsp;<i class="fa fa-barcode"></i></label>
<label for="product_id">{{ $L('Product') }}&nbsp;&nbsp;<i class="fa fa-barcode"></i></label>
<select class="form-control combobox" id="product_id" name="product_id" required>
<option value=""></option>
@foreach($products as $product)
@ -23,18 +23,18 @@
</div>
<div class="form-group">
<label for="amount">Amount&nbsp;&nbsp;<span id="amount_qu_unit" class="small text-muted"></span></label>
<label for="amount">{{ $L('Amount') }}&nbsp;&nbsp;<span id="amount_qu_unit" class="small text-muted"></span></label>
<input type="number" class="form-control" id="amount" name="amount" value="1" min="1" required>
<div class="help-block with-errors"></div>
</div>
<div class="checkbox">
<label for="spoiled">
<input type="checkbox" id="spoiled" name="spoiled"> Spoiled
<input type="checkbox" id="spoiled" name="spoiled"> {{ $L('Spoiled') }}
</label>
</div>
<button id="save-consume-button" type="submit" class="btn btn-default">OK</button>
<button id="save-consume-button" type="submit" class="btn btn-default">{{ $L('OK') }}</button>
</form>

View File

@ -1,9 +1,9 @@
@extends('layout.default')
@if($mode == 'edit')
@section('title', 'Edit habit')
@section('title', $L('Edit habit'))
@else
@section('title', 'Create habit')
@section('title', $L('Create habit'))
@endif
@section('viewJsName', 'habitform')
@ -22,35 +22,35 @@
<form id="habit-form">
<div class="form-group">
<label for="name">Name</label>
<label for="name">{{ $L('Name') }}</label>
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $habit->name }}@endif">
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="description">Description</label>
<label for="description">{{ $L('Description') }}</label>
<textarea class="form-control" rows="2" id="description" name="description">@if($mode == 'edit'){{ $habit->description }}@endif</textarea>
</div>
<div class="form-group">
<label for="period_type">Period type</label>
<label for="period_type">{{ $L('Period type') }}</label>
<select required class="form-control input-group-habit-period-type" id="period_type" name="period_type">
@foreach($periodTypes as $periodType)
<option @if($mode == 'edit' && $periodType == $habit->period_type) selected="selected" @endif value="{{ $periodType }}">{{ $periodType }}</option>
<option @if($mode == 'edit' && $periodType == $habit->period_type) selected="selected" @endif value="{{ $periodType }}">{{ $L($periodType) }}</option>
@endforeach
</select>
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="period_days">Period days</label>
<label for="period_days">{{ $L('Period days') }}</label>
<input type="number" class="form-control input-group-habit-period-type" id="period_days" name="period_days" value="@if($mode == 'edit'){{ $habit->period_days }}@endif">
<div class="help-block with-errors"></div>
</div>
<p id="habit-period-type-info" class="help-block text-muted"></p>
<button id="save-habit-button" type="submit" class="btn btn-default">Save</button>
<button id="save-habit-button" type="submit" class="btn btn-default">{{ $L('Save') }}</button>
</form>

View File

@ -1,6 +1,6 @@
@extends('layout.default')
@section('title', 'Habits')
@section('title', $L('Habits'))
@section('activeNav', 'habits')
@section('viewJsName', 'habits')
@ -8,9 +8,9 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<h1 class="page-header">
Habits
@yield('title')
<a class="btn btn-default" href="/habit/new" role="button">
<i class="fa fa-plus"></i>&nbsp;Add
<i class="fa fa-plus"></i>&nbsp;{{ $L('Add') }}
</a>
</h1>
@ -19,10 +19,10 @@
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Period type</th>
<th>Period days</th>
<th>Description</th>
<th>{{ $L('Name') }}</th>
<th>{{ $L('Period type') }}</th>
<th>{{ $L('Period days') }}</th>
<th>{{ $L('Description') }}</th>
</tr>
</thead>
<tbody>
@ -40,7 +40,7 @@
{{ $habit->name }}
</td>
<td>
{{ $habit->period_type }}
{{ $L($habit->period_type) }}
</td>
<td>
{{ $habit->period_days }}

View File

@ -1,21 +1,21 @@
@extends('layout.default')
@section('title', 'Habits overview')
@section('title', $L('Habits overview'))
@section('activeNav', 'habitsoverview')
@section('viewJsName', 'habitsoverview')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<h1 class="page-header">Habits overview</h1>
<h1 class="page-header">@yield('title')</h1>
<div class="table-responsive">
<table id="habits-overview-table" class="table table-striped">
<thead>
<tr>
<th>Habit</th>
<th>Next estimated tracking</th>
<th>Last tracked</th>
<th>{{ $L('Habit') }}</th>
<th>{{ $L('Next estimated tracking') }}</th>
<th>{{ $L('Last tracked') }}</th>
</tr>
</thead>
<tbody>

View File

@ -1,18 +1,18 @@
@extends('layout.default')
@section('title', 'Habit tracking')
@section('title', $L('Habit tracking'))
@section('activeNav', 'habittracking')
@section('viewJsName', 'habittracking')
@section('content')
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2">
<h1 class="page-header">Habit tracking</h1>
<h1 class="page-header">@yield('title')</h1>
<form id="habittracking-form">
<div class="form-group">
<label for="habit_id">Habit</label>
<label for="habit_id">{{ $L('Habit') }}</label>
<select class="form-control combobox" id="habit_id" name="habit_id" required>
<option value=""></option>
@foreach($habits as $habit)
@ -27,7 +27,7 @@
'label' => 'Tracked time'
))
<button id="save-habittracking-button" type="submit" class="btn btn-default">OK</button>
<button id="save-habittracking-button" type="submit" class="btn btn-default">{{ $L('OK') }}</button>
</form>

View File

@ -1,18 +1,18 @@
@extends('layout.default')
@section('title', 'Inventory')
@section('title', $L('Inventory'))
@section('activeNav', 'inventory')
@section('viewJsName', 'inventory')
@section('content')
<div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2">
<h1 class="page-header">Inventory</h1>
<h1 class="page-header">@yield('title')</h1>
<form id="inventory-form">
<div class="form-group">
<label for="product_id">Product&nbsp;&nbsp;<i class="fa fa-barcode"></i><span id="barcode-lookup-disabled-hint" class="small text-muted hide">&nbsp;&nbsp;Barcode lookup is disabled</span></label>
<label for="product_id">{{ $L('Product') }}&nbsp;&nbsp;<i class="fa fa-barcode"></i><span id="barcode-lookup-disabled-hint" class="small text-muted hide">&nbsp;&nbsp;{{ $L('Barcode lookup is disabled') }}</span></label>
<select class="form-control combobox" id="product_id" name="product_id" required>
<option value=""></option>
@foreach($products as $product)
@ -20,11 +20,11 @@
@endforeach
</select>
<div class="help-block with-errors"></div>
<div id="flow-info-addbarcodetoselection" class="text-muted small hide"><strong><span id="addbarcodetoselection"></span></strong> will be added to the list of barcodes for the selected product on submit.</div>
<div id="flow-info-addbarcodetoselection" class="text-muted small hide"><strong><span id="addbarcodetoselection"></span></strong> {{ $L('will be added to the list of barcodes for the selected product on submit') }}</div>
</div>
<div class="form-group">
<label for="new_amount">New amount&nbsp;&nbsp;<span id="new_amount_qu_unit" class="small text-muted"></span></label>
<label for="new_amount">{{ $L('New amount') }}&nbsp;&nbsp;<span id="new_amount_qu_unit" class="small text-muted"></span></label>
<input type="number" data-notequal="notequal" class="form-control" id="new_amount" name="new_amount" min="0" not-equal="-1" required>
<div class="help-block with-errors"></div>
<div id="inventory-change-info" class="help-block text-muted"></div>
@ -32,10 +32,11 @@
@include('components.datepicker', array(
'id' => 'best_before_date',
'label' => 'Best before&nbsp;&nbsp;<span class="small text-muted">This will apply to added products</span>'
'label' => 'Best before',
'hint' => 'This will apply to added products'
))
<button id="save-inventory-button" type="submit" class="btn btn-default">OK</button>
<button id="save-inventory-button" type="submit" class="btn btn-default">{{ $L('OK') }}</button>
</form>

View File

@ -25,10 +25,12 @@
<link href="/components_unmanaged/noto-sans-v6-latin/noto-sans-v6-latin.css?v={{ $version }}" rel="stylesheet">
<link href="/css/grocy.css?v={{ $version }}" rel="stylesheet">
<script src="/bower_components/jquery/dist/jquery.min.js?v={{ $version }}"></script>
<script src="/js/extensions.js?v={{ $version }}"></script>
<script src="/js/grocy.js?v={{ $version }}"></script>
<script>Grocy.ActiveNav = '@yield('activeNav', '')';</script>
<script>
var Grocy = { };
Grocy.Components = { };
Grocy.LocalizationStrings = {!! json_encode($localizationStrings) !!};
Grocy.ActiveNav = '@yield('activeNav', '')';
</script>
</head>
<body>
@ -46,7 +48,7 @@
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li>
<a class="discrete-link logout-button" href="/logout"><i class="fa fa-sign-out fa-fw"></i>&nbsp;Logout</a>
<a class="discrete-link logout-button" href="/logout"><i class="fa fa-sign-out fa-fw"></i>&nbsp;{{ $L('Logout') }}</a>
</li>
</ul>
</div>
@ -55,60 +57,60 @@
<ul class="nav navbar-nav navbar-right">
<li data-nav-for-page="stockoverview">
<a class="discrete-link" href="/stockoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;Stock overview</a>
<a class="discrete-link" href="/stockoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;{{ $L('Stock overview') }}</a>
</li>
<li data-nav-for-page="habitsoverview">
<a class="discrete-link" href="/habitsoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;Habits overview</a>
<a class="discrete-link" href="/habitsoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;{{ $L('Habits overview') }}</a>
</li>
<li data-nav-for-page="batteriesoverview">
<a class="discrete-link" href="/batteriesoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;Batteries overview</a>
<a class="discrete-link" href="/batteriesoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;{{ $L('Batteries overview') }}</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="disabled"><a href="#"><strong>Record data</strong></a></li>
<li class="disabled"><a href="#"><strong>{{ $L('Record data') }}</strong></a></li>
<li data-nav-for-page="purchase">
<a class="discrete-link" href="/purchase"><i class="fa fa-shopping-cart fa-fw"></i>&nbsp;Purchase</a>
<a class="discrete-link" href="/purchase"><i class="fa fa-shopping-cart fa-fw"></i>&nbsp;{{ $L('Purchase') }}</a>
</li>
<li data-nav-for-page="consume">
<a class="discrete-link" href="/consume"><i class="fa fa-cutlery fa-fw"></i>&nbsp;Consume</a>
</li>
<li data-nav-for-page="inventory">
<a class="discrete-link" href="/inventory"><i class="fa fa-list fa-fw"></i>&nbsp;Inventory</a>
<a class="discrete-link" href="/consume"><i class="fa fa-cutlery fa-fw"></i>&nbsp;{{ $L('Consume') }}</a>
</li>
<li data-nav-for-page="shoppinglist">
<a class="discrete-link" href="/shoppinglist"><i class="fa fa-shopping-bag fa-fw"></i>&nbsp;Shopping list</a>
<a class="discrete-link" href="/shoppinglist"><i class="fa fa-shopping-bag fa-fw"></i>&nbsp;{{ $L('Shopping list') }}</a>
</li>
<li data-nav-for-page="inventory">
<a class="discrete-link" href="/inventory"><i class="fa fa-list fa-fw"></i>&nbsp;{{ $L('Inventory') }}</a>
</li>
<li data-nav-for-page="habittracking">
<a class="discrete-link" href="/habittracking"><i class="fa fa-play fa-fw"></i>&nbsp;Habit tracking</a>
<a class="discrete-link" href="/habittracking"><i class="fa fa-play fa-fw"></i>&nbsp;{{ $L('Habit tracking') }}</a>
</li>
<li data-nav-for-page="batterytracking">
<a class="discrete-link" href="/batterytracking"><i class="fa fa-fire fa-fw"></i>&nbsp;Battery tracking</a>
<a class="discrete-link" href="/batterytracking"><i class="fa fa-fire fa-fw"></i>&nbsp;{{ $L('Battery tracking') }}</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="disabled"><a href="#"><strong>Manage master data</strong></a></li>
<li class="disabled"><a href="#"><strong>{{ $L('Manage master data') }}</strong></a></li>
<li data-nav-for-page="products">
<a class="discrete-link" href="/products"><i class="fa fa-product-hunt fa-fw"></i>&nbsp;Products</a>
<a class="discrete-link" href="/products"><i class="fa fa-product-hunt fa-fw"></i>&nbsp;{{ $L('Products') }}</a>
</li>
<li data-nav-for-page="locations">
<a class="discrete-link" href="/locations"><i class="fa fa-map-marker fa-fw"></i>&nbsp;Locations</a>
<a class="discrete-link" href="/locations"><i class="fa fa-map-marker fa-fw"></i>&nbsp;{{ $L('Locations') }}</a>
</li>
<li data-nav-for-page="quantityunits">
<a class="discrete-link" href="/quantityunits"><i class="fa fa-balance-scale fa-fw"></i>&nbsp;Quantity units</a>
<a class="discrete-link" href="/quantityunits"><i class="fa fa-balance-scale fa-fw"></i>&nbsp;{{ $L('Quantity units') }}</a>
</li>
<li data-nav-for-page="habits">
<a class="discrete-link" href="/habits"><i class="fa fa-refresh fa-fw"></i>&nbsp;Habits</a>
<a class="discrete-link" href="/habits"><i class="fa fa-refresh fa-fw"></i>&nbsp;{{ $L('Habits') }}</a>
</li>
<li data-nav-for-page="batteries">
<a class="discrete-link" href="/batteries"><i class="fa fa-battery-three-quarters fa-fw"></i>&nbsp;Batteries</a>
<a class="discrete-link" href="/batteries"><i class="fa fa-battery-three-quarters fa-fw"></i>&nbsp;{{ $L('Batteries') }}</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li>
<a class="discrete-link logout-button" href="/logout"><i class="fa fa-sign-out fa-fw"></i>&nbsp;Logout</a>
<a class="discrete-link logout-button" href="/logout"><i class="fa fa-sign-out fa-fw"></i>&nbsp;{{ $L('Logout') }}</a>
</li>
</ul>
@ -138,54 +140,54 @@
<ul class="nav nav-sidebar">
<li data-nav-for-page="stockoverview">
<a class="discrete-link" href="/stockoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;Stock overview</a>
<a class="discrete-link" href="/stockoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;{{ $L('Stock overview') }}</a>
</li>
<li data-nav-for-page="habitsoverview">
<a class="discrete-link" href="/habitsoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;Habits overview</a>
<a class="discrete-link" href="/habitsoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;{{ $L('Habits overview') }}</a>
</li>
<li data-nav-for-page="batteriesoverview">
<a class="discrete-link" href="/batteriesoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;Batteries overview</a>
<a class="discrete-link" href="/batteriesoverview"><i class="fa fa-tachometer fa-fw"></i>&nbsp;{{ $L('Batteries overview') }}</a>
</li>
</ul>
<ul class="nav nav-sidebar">
<li class="disabled"><a href="#"><strong>Record data</strong></a></li>
<li class="disabled"><a href="#"><strong>{{ $L('Record data') }}</strong></a></li>
<li data-nav-for-page="purchase">
<a class="discrete-link" href="/purchase"><i class="fa fa-shopping-cart fa-fw"></i>&nbsp;Purchase</a>
<a class="discrete-link" href="/purchase"><i class="fa fa-shopping-cart fa-fw"></i>&nbsp;{{ $L('Purchase') }}</a>
</li>
<li data-nav-for-page="consume">
<a class="discrete-link" href="/consume"><i class="fa fa-cutlery fa-fw"></i>&nbsp;Consume</a>
</li>
<li data-nav-for-page="inventory">
<a class="discrete-link" href="/inventory"><i class="fa fa-list fa-fw"></i>&nbsp;Inventory</a>
<a class="discrete-link" href="/consume"><i class="fa fa-cutlery fa-fw"></i>&nbsp;{{ $L('Consume') }}</a>
</li>
<li data-nav-for-page="shoppinglist">
<a class="discrete-link" href="/shoppinglist"><i class="fa fa-shopping-bag fa-fw"></i>&nbsp;Shopping list</a>
<a class="discrete-link" href="/shoppinglist"><i class="fa fa-shopping-bag fa-fw"></i>&nbsp;{{ $L('Shopping list') }}</a>
</li>
<li data-nav-for-page="inventory">
<a class="discrete-link" href="/inventory"><i class="fa fa-list fa-fw"></i>&nbsp;{{ $L('Inventory') }}</a>
</li>
<li data-nav-for-page="habittracking">
<a class="discrete-link" href="/habittracking"><i class="fa fa-play fa-fw"></i>&nbsp;Habit tracking</a>
<a class="discrete-link" href="/habittracking"><i class="fa fa-play fa-fw"></i>&nbsp;{{ $L('Habit tracking') }}</a>
</li>
<li data-nav-for-page="batterytracking">
<a class="discrete-link" href="/batterytracking"><i class="fa fa-fire fa-fw"></i>&nbsp;Battery tracking</a>
<a class="discrete-link" href="/batterytracking"><i class="fa fa-fire fa-fw"></i>&nbsp;{{ $L('Battery tracking') }}</a>
</li>
</ul>
<ul class="nav nav-sidebar">
<li class="disabled"><a href="#"><strong>Manage master data</strong></a></li>
<li class="disabled"><a href="#"><strong>{{ $L('Manage master data') }}</strong></a></li>
<li data-nav-for-page="products">
<a class="discrete-link" href="/products"><i class="fa fa-product-hunt fa-fw"></i>&nbsp;Products</a>
<a class="discrete-link" href="/products"><i class="fa fa-product-hunt fa-fw"></i>&nbsp;{{ $L('Products') }}</a>
</li>
<li data-nav-for-page="locations">
<a class="discrete-link" href="/locations"><i class="fa fa-map-marker fa-fw"></i>&nbsp;Locations</a>
<a class="discrete-link" href="/locations"><i class="fa fa-map-marker fa-fw"></i>&nbsp;{{ $L('Locations') }}</a>
</li>
<li data-nav-for-page="quantityunits">
<a class="discrete-link" href="/quantityunits"><i class="fa fa-balance-scale fa-fw"></i>&nbsp;Quantity units</a>
<a class="discrete-link" href="/quantityunits"><i class="fa fa-balance-scale fa-fw"></i>&nbsp;{{ $L('Quantity units') }}</a>
</li>
<li data-nav-for-page="habits">
<a class="discrete-link" href="/habits"><i class="fa fa-refresh fa-fw"></i>&nbsp;Habits</a>
<a class="discrete-link" href="/habits"><i class="fa fa-refresh fa-fw"></i>&nbsp;{{ $L('Habits') }}</a>
</li>
<li data-nav-for-page="batteries">
<a class="discrete-link" href="/batteries"><i class="fa fa-battery-three-quarters fa-fw"></i>&nbsp;Batteries</a>
<a class="discrete-link" href="/batteries"><i class="fa fa-battery-three-quarters fa-fw"></i>&nbsp;{{ $L('Batteries') }}</a>
</li>
</ul>
@ -211,11 +213,14 @@
</div>
</div>
<script src="/bower_components/jquery/dist/jquery.min.js?v={{ $version }}"></script>
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js?v={{ $version }}"></script>
<script src="/bower_components/bootbox/bootbox.js?v={{ $version }}"></script>
<script src="/bower_components/jquery.serializeJSON/jquery.serializejson.min.js?v={{ $version }}"></script>
<script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js?v={{ $version }}"></script>
@if(!empty($L('bootstrap_datepicker_locale')))<script src="/bower_components/bootstrap-datepicker/dist/locales/bootstrap-datepicker.{{ $L('bootstrap_datepicker_locale') }}.min.js?v={{ $version }}"></script>@endif
<script src="/bower_components/moment/min/moment.min.js?v={{ $version }}"></script>
@if(!empty($L('moment_locale')))<script src="/bower_components/moment/locale/{{ $L('moment_locale') }}.js?v={{ $version }}"></script>@endif
<script src="/bower_components/bootstrap-validator/dist/validator.min.js?v={{ $version }}"></script>
<script src="/bower_components/bootstrap-combobox/js/bootstrap-combobox.js?v={{ $version }}"></script>
<script src="/bower_components/datatables.net/js/jquery.dataTables.min.js?v={{ $version }}"></script>
@ -223,10 +228,13 @@
<script src="/bower_components/datatables.net-responsive/js/dataTables.responsive.min.js?v={{ $version }}"></script>
<script src="/bower_components/datatables.net-responsive-bs/js/responsive.bootstrap.min.js?v={{ $version }}"></script>
<script src="/bower_components/jquery-timeago/jquery.timeago.js?v={{ $version }}"></script>
<script src="/bower_components/jquery-timeago/locales/jquery.timeago.{{ $L('timeago_locale') }}.js?v={{ $version }}"></script>
<script src="/bower_components/toastr/toastr.min.js?v={{ $version }}"></script>
<script src="/bower_components/tagmanager/tagmanager.js?v={{ $version }}"></script>
<script src="/bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js?v={{ $version }}"></script>
<script src="/js/extensions.js?v={{ $version }}"></script>
<script src="/js/grocy.js?v={{ $version }}"></script>
<script src="/viewjs/@yield('viewJsName').js"></script>
@stack('componentScripts')

View File

@ -1,9 +1,9 @@
@extends('layout.default')
@if($mode == 'edit')
@section('title', 'Edit location')
@section('title', $L('Edit location'))
@else
@section('title', 'Create location')
@section('title', $L('Create location'))
@endif
@section('viewJsName', 'locationform')
@ -22,17 +22,17 @@
<form id="location-form">
<div class="form-group">
<label for="name">Name</label>
<label for="name">{{ $L('Name') }}</label>
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $location->name }}@endif">
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="description">Description</label>
<label for="description">{{ $L('Description') }}</label>
<textarea class="form-control" rows="2" id="description" name="description">@if($mode == 'edit'){{ $location->description }}@endif</textarea>
</div>
<button id="save-location-button" type="submit" class="btn btn-default">Save</button>
<button id="save-location-button" type="submit" class="btn btn-default">{{ $L('Save') }}</button>
</form>

View File

@ -1,6 +1,6 @@
@extends('layout.default')
@section('title', 'Locations')
@section('title', $L('Locations'))
@section('activeNav', 'locations')
@section('viewJsName', 'locations')
@ -8,9 +8,9 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<h1 class="page-header">
Locations
@yield('title')
<a class="btn btn-default" href="/location/new" role="button">
<i class="fa fa-plus"></i>&nbsp;Add
<i class="fa fa-plus"></i>&nbsp;{{ $L('Add') }}
</a>
</h1>
@ -19,8 +19,8 @@
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Description</th>
<th>{{ $L('Name') }}</th>
<th>{{ $L('Description') }}</th>
</tr>
</thead>
<tbody>

View File

@ -1,28 +1,28 @@
@extends('layout.default')
@section('title', 'Login')
@section('title', $L('Login'))
@section('viewJsName', 'login')
@section('content')
<div class="col-md-4 col-md-offset-5">
<h1 class="page-header text-center">Login</h1>
<h1 class="page-header text-center">@yield('title')</h1>
<form method="post" action="/login" id="login-form">
<div class="form-group">
<label for="name">Username</label>
<label for="name">{{ $L('Username') }}</label>
<input type="text" class="form-control" required id="username" name="username">
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="name">Password</label>
<label for="name">{{ $L('Password') }}</label>
<input type="password" class="form-control" required id="password" name="password">
<div id="login-error" class="help-block with-errors"></div>
</div>
<button id="login-button" type="submit" class="btn btn-default">Login</button>
<button id="login-button" type="submit" class="btn btn-default">{{ $L('OK') }}</button>
</form>

View File

@ -1,9 +1,9 @@
@extends('layout.default')
@if($mode == 'edit')
@section('title', 'Edit product')
@section('title', $L('Edit product'))
@else
@section('title', 'Create product')
@section('title', $L('Create product'))
@endif
@section('viewJsName', 'productform')
@ -22,24 +22,24 @@
<form id="product-form">
<div class="form-group">
<label for="name">Name</label>
<label for="name">{{ $L('Name') }}</label>
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $product->name}}@endif">
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="description">Description</label>
<label for="description">{{ $L('Description') }}</label>
<textarea class="form-control" rows="2" id="description" name="description">@if($mode == 'edit'){{ $product->description }}@endif</textarea>
</div>
<div class="form-group tm-group">
<label for="barcode-taginput">Barcode(s)&nbsp;&nbsp;<i class="fa fa-barcode"></i></label>
<label for="barcode-taginput">{{ $L('Barcode(s)') }}&nbsp;&nbsp;<i class="fa fa-barcode"></i></label>
<input type="text" class="form-control tm-input" id="barcode-taginput">
<div id="barcode-taginput-container"></div>
</div>
<div class="form-group">
<label for="location_id">Location</label>
<label for="location_id">{{ $L('Location') }}</label>
<select required class="form-control" id="location_id" name="location_id">
@foreach($locations as $location)
<option @if($mode == 'edit' && $location->id == $product->location_id) selected="selected" @endif value="{{ $location->id }}">{{ $location->name }}</option>
@ -49,19 +49,19 @@
</div>
<div class="form-group">
<label for="min_stock_amount">Minimum stock amount</label>
<label for="min_stock_amount">{{ $L('Minimum stock amount') }}</label>
<input required min="0" type="number" class="form-control" id="min_stock_amount" name="min_stock_amount" value="@if($mode == 'edit'){{ $product->min_stock_amount }}@else{{0}}@endif">
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="default_best_before_days">Default best before days<br><span class="small text-muted">For purchases this amount of days will be added to today for the best before date suggestion</span></label>
<label for="default_best_before_days">{{ $L('Default best before days') }}<br><span class="small text-muted">{{ $L('For purchases this amount of days will be added to today for the best before date suggestion') }}</span></label>
<input required min="0" type="number" class="form-control" id="default_best_before_days" name="default_best_before_days" value="@if($mode == 'edit'){{ $product->default_best_before_days }}@else{{0}}@endif">
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="qu_id_purchase">Quantity unit purchase</label>
<label for="qu_id_purchase">{{ $L('Quantity unit purchase') }}</label>
<select required class="form-control input-group-qu" id="qu_id_purchase" name="qu_id_purchase">
@foreach($quantityunits as $quantityunit)
<option @if($mode == 'edit' && $quantityunit->id == $product->qu_id_purchase) selected="selected" @endif value="{{ $quantityunit->id }}">{{ $quantityunit->name }}</option>
@ -71,7 +71,7 @@
</div>
<div class="form-group">
<label for="qu_id_stock">Quantity unit stock</label>
<label for="qu_id_stock">{{ $L('Quantity unit stock') }}</label>
<select required class="form-control input-group-qu" id="qu_id_stock" name="qu_id_stock">
@foreach($quantityunits as $quantityunit)
<option @if($mode == 'edit' && $quantityunit->id == $product->qu_id_stock) selected="selected" @endif value="{{ $quantityunit->id }}">{{ $quantityunit->name }}</option>
@ -81,14 +81,14 @@
</div>
<div class="form-group">
<label for="qu_factor_purchase_to_stock">Factor purchase to stock quantity unit</label>
<label for="qu_factor_purchase_to_stock">{{ $L('Factor purchase to stock quantity unit') }}</label>
<input required min="1" type="number" class="form-control input-group-qu" id="qu_factor_purchase_to_stock" name="qu_factor_purchase_to_stock" value="@if ($mode == 'edit'){{ $product->qu_factor_purchase_to_stock }}@else{{1}}@endif">
<div class="help-block with-errors"></div>
</div>
<p id="qu-conversion-info" class="help-block text-muted"></p>
<button id="save-product-button" type="submit" class="btn btn-default">Save</button>
<button id="save-product-button" type="submit" class="btn btn-default">{{ $L('Save') }}</button>
</form>
</div>

View File

@ -1,6 +1,6 @@
@extends('layout.default')
@section('title', 'Products')
@section('title', $L('Products'))
@section('activeNav', 'products')
@section('viewJsName', 'products')
@ -8,9 +8,9 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<h1 class="page-header">
Products
@yield('title')
<a class="btn btn-default" href="/product/new" role="button">
<i class="fa fa-plus"></i>&nbsp;Add
<i class="fa fa-plus"></i>&nbsp;{{ $L('Add') }}
</a>
</h1>
@ -19,13 +19,13 @@
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Location</th>
<th>Min. stock amount</th>
<th>QU purchase</th>
<th>QU stock</th>
<th>QU factor</th>
<th>Description</th>
<th>{{ $L('Name') }}</th>
<th>{{ $L('Location') }}</th>
<th>{{ $L('Min. stock amount') }}</th>
<th>{{ $L('QU purchase') }}</th>
<th>{{ $L('QU stock') }}</th>
<th>{{ $L('QU factor') }}</th>
<th>{{ $L('Description') }}</th>
</tr>
</thead>
<tbody>

View File

@ -1,18 +1,18 @@
@extends('layout.default')
@section('title', 'Purchase')
@section('title', $L('Purchase'))
@section('activeNav', 'purchase')
@section('viewJsName', 'purchase')
@section('content')
<div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2">
<h1 class="page-header">Purchase</h1>
<h1 class="page-header">@yield('title')</h1>
<form id="purchase-form">
<div class="form-group">
<label for="product_id">Product&nbsp;&nbsp;<i class="fa fa-barcode"></i><span id="barcode-lookup-disabled-hint" class="small text-muted hide">&nbsp;&nbsp;Barcode lookup is disabled</span></label>
<label for="product_id">{{ $L('Product') }}&nbsp;&nbsp;<i class="fa fa-barcode"></i><span id="barcode-lookup-disabled-hint" class="small text-muted hide">&nbsp;&nbsp;Barcode lookup is disabled</span></label>
<select class="form-control combobox" id="product_id" name="product_id" required>
<option value=""></option>
@foreach($products as $product)
@ -29,12 +29,12 @@
))
<div class="form-group">
<label for="amount">Amount&nbsp;&nbsp;<span id="amount_qu_unit" class="small text-muted"></span></label>
<label for="amount">{{ $L('Amount') }}&nbsp;&nbsp;<span id="amount_qu_unit" class="small text-muted"></span></label>
<input type="number" class="form-control" id="amount" name="amount" value="1" min="1" required>
<div class="help-block with-errors"></div>
</div>
<button id="save-purchase-button" type="submit" class="btn btn-default">OK</button>
<button id="save-purchase-button" type="submit" class="btn btn-default">{{ $L('OK') }}</button>
</form>

View File

@ -1,9 +1,9 @@
@extends('layout.default')
@if($mode == 'edit')
@section('title', 'Edit quantity unit')
@section('title', $L('Edit quantity unit'))
@else
@section('title', 'Create quantity unit')
@section('title', $L('Create quantity unit'))
@endif
@section('viewJsName', 'quantityunitform')
@ -22,17 +22,17 @@
<form id="quantityunit-form">
<div class="form-group">
<label for="name">Name</label>
<label for="name">{{ $L('Name') }}</label>
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $quantityunit->name }}@endif">
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="description">Description</label>
<label for="description">{{ $L('Description') }}</label>
<textarea class="form-control" rows="2" id="description" name="description">@if($mode == 'edit'){{ $quantityunit->description }}@endif</textarea>
</div>
<button id="save-quantityunit-button" type="submit" class="btn btn-default">Save</button>
<button id="save-quantityunit-button" type="submit" class="btn btn-default">{{ $L('Save') }}</button>
</form>

View File

@ -1,6 +1,6 @@
@extends('layout.default')
@section('title', 'Quantity units')
@section('title', $L('Quantity units'))
@section('activeNav', 'quantityunits')
@section('viewJsName', 'quantityunits')
@ -8,7 +8,7 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<h1 class="page-header">
Quantity units
@yield('title')
<a class="btn btn-default" href="/quantityunit/new" role="button">
<i class="fa fa-plus"></i>&nbsp;Add
</a>
@ -19,8 +19,8 @@
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Description</th>
<th>{{ $L('Name') }}</th>
<th>{{ $L('Description') }}</th>
</tr>
</thead>
<tbody>

View File

@ -1,6 +1,6 @@
@extends('layout.default')
@section('title', 'Shopping list')
@section('title', $L('Shopping list'))
@section('activeNav', 'shoppinglist')
@section('viewJsName', 'shoppinglist')
@ -8,12 +8,12 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<h1 class="page-header">
Shopping list
@yield('title')
<a class="btn btn-default" href="/shoppinglistitem/new" role="button">
<i class="fa fa-plus"></i>&nbsp;Add
<i class="fa fa-plus"></i>&nbsp;{{ $L('Add') }}
</a>
<a id="add-products-below-min-stock-amount" class="btn btn-info" href="#" role="button">
<i class="fa fa-plus"></i>&nbsp;Add products that are below defined min. stock amount
<i class="fa fa-plus"></i>&nbsp;{{ $L('Add products that are below defined min. stock amount') }}
</a>
</h1>
@ -22,8 +22,8 @@
<thead>
<tr>
<th>#</th>
<th>Product / <em>Note</em></th>
<th>Amount</th>
<th>{{ $L('Product') }} / <em>{{ $L('Note') }}</em></th>
<th>{{ $L('Amount') }}</th>
</tr>
</thead>
<tbody>

View File

@ -1,9 +1,9 @@
@extends('layout.default')
@if($mode == 'edit')
@section('title', 'Edit shopping list item')
@section('title', $L('Edit shopping list item'))
@else
@section('title', 'Create shopping list item')
@section('title', $L('Create shopping list item'))
@endif
@section('viewJsName', 'shoppinglistform')
@ -22,7 +22,7 @@
<form id="shoppinglist-form">
<div class="form-group">
<label for="product_id">Product&nbsp;&nbsp;<i class="fa fa-barcode"></i></label>
<label for="product_id">{{ $L('Product') }}&nbsp;&nbsp;<i class="fa fa-barcode"></i></label>
<select class="form-control combobox" id="product_id" name="product_id" value="@if($mode == 'edit') {{ $listItem->product_id }} @endif">
<option value=""></option>
@foreach($products as $product)
@ -33,30 +33,23 @@
</div>
<div class="form-group">
<label for="amount">Amount&nbsp;&nbsp;<span id="amount_qu_unit" class="small text-muted"></span><br><span class="small text-warning">@if($mode == 'edit' && $listItem->amount_autoadded > 0){{ $listItem->amount_autoadded }} units were automatically added and will apply in addition to the amount entered here.@endif</span></label>
<label for="amount">{{ $L('Amount') }}&nbsp;&nbsp;<span id="amount_qu_unit" class="small text-muted"></span><br><span class="small text-warning">@if($mode == 'edit' && $listItem->amount_autoadded > 0){{ $L('#1 units were automatically added and will apply in addition to the amount entered here', $listItem->amount_autoadded) }}@endif</span></label>
<input type="number" class="form-control" id="amount" name="amount" value="@if($mode == 'edit'){{ $listItem->amount }}@else{{1}}@endif" min="0" required>
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<label for="note">Note</label>
<label for="note">{{ $L('Note') }}</label>
<textarea class="form-control" rows="2" id="note" name="note">@if($mode == 'edit'){{ $listItem->note }}@endif</textarea>
</div>
<button id="save-shoppinglist-button" type="submit" class="btn btn-default">Save</button>
<button id="save-shoppinglist-button" type="submit" class="btn btn-default">{{ $L('Save') }}</button>
</form>
</div>
<div class="col-sm-6 col-md-5 col-lg-3 main well">
<h3>Product overview <strong><span id="selected-product-name"></span></strong></h3>
<h4><strong>Stock quantity unit:</strong> <span id="selected-product-stock-qu-name"></span></h4>
<p>
<strong>Stock amount:</strong> <span id="selected-product-stock-amount"></span> <span id="selected-product-stock-qu-name2"></span><br>
<strong>Last purchased:</strong> <span id="selected-product-last-purchased"></span> <time id="selected-product-last-purchased-timeago" class="timeago timeago-contextual"></time><br>
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
</p>
<div class="col-sm-6 col-md-5 col-lg-3">
@include('components.productcard')
</div>
@stop

View File

@ -1,19 +1,19 @@
@extends('layout.default')
@section('title', 'Stock overview')
@section('title', $L('Stock overview'))
@section('activeNav', 'stockoverview')
@section('viewJsName', 'stockoverview')
@section('content')
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
<h1 class="page-header">Stock overview <span class="text-muded small"><strong>{{ count($currentStock) }}</strong> products with <strong>{{ SumArrayValue($currentStock, 'amount') }}</strong> units in stock</span></h1>
<h1 class="page-header">{{ $L('Stock overview') }} <span class="text-muded small">{{ $L('#1 products with #2 units in stock', count($currentStock), SumArrayValue($currentStock, 'amount')) }}</span></h1>
<div class="container-fluid">
<div class="row">
<p class="btn btn-lg btn-warning no-real-button"><strong>{{ count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('+5 days')), '<')) }}</strong> products expiring within the next 5 days</p>
<p class="btn btn-lg btn-danger no-real-button"><strong>{{ count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('-1 days')), '<')) }}</strong> products are already expired</p>
<p class="btn btn-lg btn-info no-real-button"><strong>{{ count($missingProducts) }}</strong> products are below defined min. stock amount</p>
<p class="btn btn-lg btn-warning no-real-button">{{ $L('#1 products expiring within the next #2 days', count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('+5 days')), '<')), 5) }}</p>
<p class="btn btn-lg btn-danger no-real-button">{{ $L('#1 products are already expired', count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('-1 days')), '<'))) }}</p>
<p class="btn btn-lg btn-info no-real-button">{{ $L('#1 products are below defined min. stock amount', count($missingProducts)) }}</p>
</div>
</div>
@ -23,9 +23,9 @@
<table id="stock-overview-table" class="table table-striped">
<thead>
<tr>
<th>Product</th>
<th>Amount</th>
<th>Next best before date</th>
<th>{{ $L('Product') }}</th>
<th>{{ $L('Amount') }}</th>
<th>{{ $L('Next best before date') }}</th>
</tr>
</thead>
<tbody>