added support for fractions
This commit is contained in:
parent
9863447bac
commit
7732aa7646
@ -19,6 +19,14 @@ POSTGRES_USER=djangodb
|
|||||||
POSTGRES_PASSWORD=
|
POSTGRES_PASSWORD=
|
||||||
POSTGRES_DB=djangodb
|
POSTGRES_DB=djangodb
|
||||||
|
|
||||||
|
# the default value for the user preference 'fractions' (enable/disable fraction support)
|
||||||
|
# when unset: 0 (disabled)
|
||||||
|
FRACTION_PREF_DEFAULT=0
|
||||||
|
|
||||||
|
# the default value for the user preference 'comments' (enable/disable commenting system)
|
||||||
|
# when unset: 1 (true)
|
||||||
|
COMMENT_PREF_DEFAULT=1
|
||||||
|
|
||||||
# Users can set a amount of time after which the shopping list is refreshed when they are in viewing mode
|
# Users can set a amount of time after which the shopping list is refreshed when they are in viewing mode
|
||||||
# This is the minimum interval users can set. Setting this to low will allow users to refresh very frequently which
|
# This is the minimum interval users can set. Setting this to low will allow users to refresh very frequently which
|
||||||
# might cause high load on the server. (Technically they can obviously refresh as often as they want with their own scripts)
|
# might cause high load on the server. (Technically they can obviously refresh as often as they want with their own scripts)
|
||||||
@ -36,14 +44,9 @@ SHOPPING_MIN_AUTOSYNC_INTERVAL=5
|
|||||||
# when unset: 1 (true) - this is temporary until an appropriate amount of time has passed for everyone to migrate
|
# when unset: 1 (true) - this is temporary until an appropriate amount of time has passed for everyone to migrate
|
||||||
GUNICORN_MEDIA=0
|
GUNICORN_MEDIA=0
|
||||||
|
|
||||||
|
|
||||||
# allow authentication via reverse proxy (e.g. authelia), leave of if you dont know what you are doing
|
# allow authentication via reverse proxy (e.g. authelia), leave of if you dont know what you are doing
|
||||||
# docs: https://github.com/vabene1111/recipes/tree/develop/docs/docker/nginx-proxy%20with%20proxy%20authentication
|
# docs: https://github.com/vabene1111/recipes/tree/develop/docs/docker/nginx-proxy%20with%20proxy%20authentication
|
||||||
# when unset: 0 (false)
|
# when unset: 0 (false)
|
||||||
REVERSE_PROXY_AUTH=0
|
REVERSE_PROXY_AUTH=0
|
||||||
|
|
||||||
|
|
||||||
# the default value for the user preference 'comments' (enable/disable commenting system)
|
|
||||||
# when unset: 1 (true)
|
|
||||||
COMMENT_PREF_DEFAULT=1
|
|
||||||
|
|
||||||
|
@ -31,11 +31,12 @@ class UserPreferenceForm(forms.ModelForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = UserPreference
|
model = UserPreference
|
||||||
fields = ('default_unit', 'theme', 'nav_color', 'default_page', 'show_recent', 'search_style', 'plan_share', 'ingredient_decimals', 'shopping_auto_sync', 'comments')
|
fields = ('default_unit', 'use_fractions', 'theme', 'nav_color', 'default_page', 'show_recent', 'search_style', 'plan_share', 'ingredient_decimals', 'shopping_auto_sync', 'comments')
|
||||||
|
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'nav_color': _('Color of the top navigation bar. Not all colors work with all themes, just try them out!'),
|
'nav_color': _('Color of the top navigation bar. Not all colors work with all themes, just try them out!'),
|
||||||
'default_unit': _('Default Unit to be used when inserting a new ingredient into a recipe.'),
|
'default_unit': _('Default Unit to be used when inserting a new ingredient into a recipe.'),
|
||||||
|
'use_fractions': _('Enables support for fractions in ingredient amounts (e.g. convert decimals to fractions automatically)'),
|
||||||
'plan_share': _('Default user to share newly created meal plan entries with.'),
|
'plan_share': _('Default user to share newly created meal plan entries with.'),
|
||||||
'show_recent': _('Show recently viewed recipes on search page.'),
|
'show_recent': _('Show recently viewed recipes on search page.'),
|
||||||
'ingredient_decimals': _('Number of decimals to round ingredients.'),
|
'ingredient_decimals': _('Number of decimals to round ingredients.'),
|
||||||
|
24
cookbook/migrations/0090_auto_20201214_1359.py
Normal file
24
cookbook/migrations/0090_auto_20201214_1359.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Django 3.1.3 on 2020-12-14 12:59
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0089_auto_20201117_2222'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userpreference',
|
||||||
|
name='use_fractions',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='invitelink',
|
||||||
|
name='valid_until',
|
||||||
|
field=models.DateField(default=datetime.date(2020, 12, 28)),
|
||||||
|
),
|
||||||
|
]
|
@ -9,7 +9,7 @@ from django.utils.translation import gettext as _
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django_random_queryset import RandomManager
|
from django_random_queryset import RandomManager
|
||||||
|
|
||||||
from recipes.settings import COMMENT_PREF_DEFAULT
|
from recipes.settings import COMMENT_PREF_DEFAULT, FRACTION_PREF_DEFAULT
|
||||||
|
|
||||||
|
|
||||||
def get_user_name(self):
|
def get_user_name(self):
|
||||||
@ -69,6 +69,7 @@ class UserPreference(models.Model):
|
|||||||
theme = models.CharField(choices=THEMES, max_length=128, default=FLATLY)
|
theme = models.CharField(choices=THEMES, max_length=128, default=FLATLY)
|
||||||
nav_color = models.CharField(choices=COLORS, max_length=128, default=PRIMARY)
|
nav_color = models.CharField(choices=COLORS, max_length=128, default=PRIMARY)
|
||||||
default_unit = models.CharField(max_length=32, default='g')
|
default_unit = models.CharField(max_length=32, default='g')
|
||||||
|
use_fractions = models.BooleanField(default=FRACTION_PREF_DEFAULT)
|
||||||
default_page = models.CharField(choices=PAGES, max_length=64, default=SEARCH)
|
default_page = models.CharField(choices=PAGES, max_length=64, default=SEARCH)
|
||||||
search_style = models.CharField(choices=SEARCH_STYLE, max_length=64, default=LARGE)
|
search_style = models.CharField(choices=SEARCH_STYLE, max_length=64, default=LARGE)
|
||||||
show_recent = models.BooleanField(default=True)
|
show_recent = models.BooleanField(default=True)
|
||||||
|
43
cookbook/static/js/frac.js
Normal file
43
cookbook/static/js/frac.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* frac.js (C) 2012-present SheetJS -- http://sheetjs.com */
|
||||||
|
/*https://developer.aliyun.com/mirror/npm/package/frac/v/0.3.0 Apache license*/
|
||||||
|
var frac = function frac(x, D, mixed) {
|
||||||
|
var n1 = Math.floor(x), d1 = 1;
|
||||||
|
var n2 = n1+1, d2 = 1;
|
||||||
|
if(x !== n1) while(d1 <= D && d2 <= D) {
|
||||||
|
var m = (n1 + n2) / (d1 + d2);
|
||||||
|
if(x === m) {
|
||||||
|
if(d1 + d2 <= D) { d1+=d2; n1+=n2; d2=D+1; }
|
||||||
|
else if(d1 > d2) d2=D+1;
|
||||||
|
else d1=D+1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(x < m) { n2 = n1+n2; d2 = d1+d2; }
|
||||||
|
else { n1 = n1+n2; d1 = d1+d2; }
|
||||||
|
}
|
||||||
|
if(d1 > D) { d1 = d2; n1 = n2; }
|
||||||
|
if(!mixed) return [0, n1, d1];
|
||||||
|
var q = Math.floor(n1/d1);
|
||||||
|
return [q, n1 - q*d1, d1];
|
||||||
|
};
|
||||||
|
frac.cont = function cont(x, D, mixed) {
|
||||||
|
var sgn = x < 0 ? -1 : 1;
|
||||||
|
var B = x * sgn;
|
||||||
|
var P_2 = 0, P_1 = 1, P = 0;
|
||||||
|
var Q_2 = 1, Q_1 = 0, Q = 0;
|
||||||
|
var A = Math.floor(B);
|
||||||
|
while(Q_1 < D) {
|
||||||
|
A = Math.floor(B);
|
||||||
|
P = A * P_1 + P_2;
|
||||||
|
Q = A * Q_1 + Q_2;
|
||||||
|
if((B - A) < 0.00000005) break;
|
||||||
|
B = 1 / (B - A);
|
||||||
|
P_2 = P_1; P_1 = P;
|
||||||
|
Q_2 = Q_1; Q_1 = Q;
|
||||||
|
}
|
||||||
|
if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
|
||||||
|
if(!mixed) return [0, sgn * P, Q];
|
||||||
|
var q = Math.floor(sgn * P/Q);
|
||||||
|
return [q, sgn*P - q*Q, Q];
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
if(typeof module !== 'undefined' && typeof DO_NOT_EXPORT_FRAC === 'undefined') module.exports = frac;
|
@ -12,6 +12,8 @@
|
|||||||
{% include 'include/vue_base.html' %}
|
{% include 'include/vue_base.html' %}
|
||||||
<script src="{% static 'js/moment-with-locales.min.js' %}"></script>
|
<script src="{% static 'js/moment-with-locales.min.js' %}"></script>
|
||||||
|
|
||||||
|
<script src="{% static 'js/frac.js' %}"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="{% static 'css/pretty-checkbox.min.css' %}">
|
<link rel="stylesheet" href="{% static 'css/pretty-checkbox.min.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'custom/css/markdown_blockquote.css' %}">
|
<link rel="stylesheet" href="{% static 'custom/css/markdown_blockquote.css' %}">
|
||||||
|
|
||||||
@ -150,7 +152,7 @@
|
|||||||
<span>⁣</span>
|
<span>⁣</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!i.no_amount">
|
<template v-if="!i.no_amount">
|
||||||
<span>[[roundDecimals(i.amount * ingredient_factor)]]</span>
|
<span v-html="calculateAmount(i.amount)"></span>
|
||||||
{# Allow for amounts without units, such as "2 eggs" #}
|
{# Allow for amounts without units, such as "2 eggs" #}
|
||||||
<template v-if="i.unit">
|
<template v-if="i.unit">
|
||||||
[[i.unit.name]]
|
[[i.unit.name]]
|
||||||
@ -325,7 +327,7 @@
|
|||||||
<span>⁣</span>
|
<span>⁣</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!i.no_amount">
|
<template v-if="!i.no_amount">
|
||||||
<span>[[roundDecimals(i.amount * ingredient_factor)]]</span>
|
<span v-html="calculateAmount(i.amount)"></span>
|
||||||
{# Allow for amounts without units, such as "2 eggs" #}
|
{# Allow for amounts without units, such as "2 eggs" #}
|
||||||
<template v-if="i.unit">
|
<template v-if="i.unit">
|
||||||
[[i.unit.name]]
|
[[i.unit.name]]
|
||||||
@ -577,8 +579,28 @@
|
|||||||
},
|
},
|
||||||
getShoppingUrl: function () {
|
getShoppingUrl: function () {
|
||||||
return `{% url 'view_shopping' %}?r=[${this.recipe.id},${this.ingredient_factor}]`
|
return `{% url 'view_shopping' %}?r=[${this.recipe.id},${this.ingredient_factor}]`
|
||||||
|
},
|
||||||
|
calculateAmount: function (amount) {
|
||||||
|
{% if request.user.userpreference.use_fractions %}
|
||||||
|
let return_string = ''
|
||||||
|
let fraction = frac.cont(amount, 9, true)
|
||||||
|
|
||||||
|
if (fraction[0] > 0) {
|
||||||
|
return_string += fraction[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fraction[1] > 0) {
|
||||||
|
return_string += ` <sup>${(fraction[1])}</sup>⁄<sub>${(fraction[2])}</sub>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return return_string
|
||||||
|
{% else %}
|
||||||
|
return this.roundDecimals(amount * this.ingredient_factor)
|
||||||
|
{% endif %}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -202,6 +202,7 @@ def user_settings(request):
|
|||||||
up.plan_share.set(form.cleaned_data['plan_share'])
|
up.plan_share.set(form.cleaned_data['plan_share'])
|
||||||
up.ingredient_decimals = form.cleaned_data['ingredient_decimals']
|
up.ingredient_decimals = form.cleaned_data['ingredient_decimals']
|
||||||
up.comments = form.cleaned_data['comments']
|
up.comments = form.cleaned_data['comments']
|
||||||
|
up.use_fractions = form.cleaned_data['use_fractions']
|
||||||
|
|
||||||
up.shopping_auto_sync = form.cleaned_data['shopping_auto_sync']
|
up.shopping_auto_sync = form.cleaned_data['shopping_auto_sync']
|
||||||
if up.shopping_auto_sync < settings.SHOPPING_MIN_AUTOSYNC_INTERVAL:
|
if up.shopping_auto_sync < settings.SHOPPING_MIN_AUTOSYNC_INTERVAL:
|
||||||
|
@ -31,6 +31,7 @@ REVERSE_PROXY_AUTH = bool(int(os.getenv('REVERSE_PROXY_AUTH', False)))
|
|||||||
|
|
||||||
# default value for user preference 'comment'
|
# default value for user preference 'comment'
|
||||||
COMMENT_PREF_DEFAULT = bool(int(os.getenv('COMMENT_PREF_DEFAULT', True)))
|
COMMENT_PREF_DEFAULT = bool(int(os.getenv('COMMENT_PREF_DEFAULT', True)))
|
||||||
|
FRACTION_PREF_DEFAULT = bool(int(os.getenv('FRACTION_PREF_DEFAULT', False)))
|
||||||
|
|
||||||
# minimum interval that users can set for automatic sync of shopping lists
|
# minimum interval that users can set for automatic sync of shopping lists
|
||||||
SHOPPING_MIN_AUTOSYNC_INTERVAL = int(os.getenv('SHOPPING_MIN_AUTOSYNC_INTERVAL', 5))
|
SHOPPING_MIN_AUTOSYNC_INTERVAL = int(os.getenv('SHOPPING_MIN_AUTOSYNC_INTERVAL', 5))
|
||||||
|
Loading…
Reference in New Issue
Block a user