Compare commits
3 commits
4c6f39b61f
...
51ed36d6c3
| Author | SHA1 | Date | |
|---|---|---|---|
| 51ed36d6c3 | |||
| d9bdb32419 | |||
| f228486c5a |
4 changed files with 88 additions and 60 deletions
|
|
@ -257,7 +257,9 @@ CREATE TABLE [ShoppingEntry] (
|
||||||
-- In both cases [name], [quantity_value], [quantity_unit] and [Servings] are used to display
|
-- In both cases [name], [quantity_value], [quantity_unit] and [Servings] are used to display
|
||||||
-- the entry instead of [Ingredient] data.
|
-- the entry instead of [Ingredient] data.
|
||||||
[ingredient_id] INTEGER,
|
[ingredient_id] INTEGER,
|
||||||
[recipe_scheduled_id] INTEGER, -- Can be null when manually added.
|
|
||||||
|
-- Can be null when manually added (entry is not linked to a recipe).
|
||||||
|
[recipe_scheduled_id] INTEGER,
|
||||||
|
|
||||||
[is_checked] INTEGER NOT NULL DEFAULT FALSE,
|
[is_checked] INTEGER NOT NULL DEFAULT FALSE,
|
||||||
|
|
||||||
|
|
@ -269,16 +271,7 @@ CREATE TABLE [ShoppingEntry] (
|
||||||
|
|
||||||
CHECK (
|
CHECK (
|
||||||
length([name]) <= 255 AND
|
length([name]) <= 255 AND
|
||||||
([is_checked] = TRUE OR [is_checked] = FALSE) AND
|
([is_checked] = TRUE OR [is_checked] = FALSE)
|
||||||
(
|
|
||||||
[recipe_scheduled_id] IS NULL OR
|
|
||||||
(
|
|
||||||
[name] = '' AND
|
|
||||||
[quantity_value] IS NULL AND
|
|
||||||
[quantity_unit] = '' AND
|
|
||||||
[servings] IS NULL
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
|
|
||||||
FOREIGN KEY([user_id]) REFERENCES [User]([id]) ON DELETE CASCADE,
|
FOREIGN KEY([user_id]) REFERENCES [User]([id]) ON DELETE CASCADE,
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="weekdays">
|
<ul class="days">
|
||||||
{% let day_names = [
|
{% let day_names = [
|
||||||
Sentence::CalendarMondayAbbreviation,
|
Sentence::CalendarMondayAbbreviation,
|
||||||
Sentence::CalendarTuesdayAbbreviation,
|
Sentence::CalendarTuesdayAbbreviation,
|
||||||
|
|
@ -52,12 +52,10 @@
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</ul>
|
{# The last row may be hidden if 5 rows is enough to display all days. #}
|
||||||
|
{% for i in 0..6 %}
|
||||||
<ul class="days">
|
|
||||||
{% for i in 0..5 %}
|
|
||||||
{% for j in 0..7 %}
|
{% for j in 0..7 %}
|
||||||
{# All days of the current selected month will have the class 'current-month' #}
|
{# All days of the current selected month will have the class 'current-month'. #}
|
||||||
<li id="day-grid-{{i}}{{j}}">
|
<li id="day-grid-{{i}}{{j}}">
|
||||||
<div class="number"></div>
|
<div class="number"></div>
|
||||||
<div class="scheduled-recipes"></div>
|
<div class="scheduled-recipes"></div>
|
||||||
|
|
@ -68,11 +66,7 @@
|
||||||
|
|
||||||
<div id="hidden-templates-calendar">
|
<div id="hidden-templates-calendar">
|
||||||
<div class="scheduled-recipe-with-link-and-remove"><a></a>
|
<div class="scheduled-recipe-with-link-and-remove"><a></a>
|
||||||
<span class="remove-scheduled-recipe button tooltip">✖
|
<span class="remove-scheduled-recipe button tooltip">✖<span class="tooltiptext">{{ context.tr.t(Sentence::CalendarUnschedule) }}</span></span>
|
||||||
<span class="tooltiptext">
|
|
||||||
{{ context.tr.t(Sentence::CalendarUnschedule) }}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="scheduled-recipe"></div>
|
<div class="scheduled-recipe"></div>
|
||||||
|
|
|
||||||
|
|
@ -167,22 +167,28 @@ pub fn setup(
|
||||||
EventListener::new(&days, "click", move |event| {
|
EventListener::new(&days, "click", move |event| {
|
||||||
let target: Element = event.target().unwrap().dyn_into().unwrap();
|
let target: Element = event.target().unwrap().dyn_into().unwrap();
|
||||||
|
|
||||||
if target.class_name() == "number" && options.can_select_date {
|
// FIXME: Replace by an if let + condition when available in stable.
|
||||||
let first_day = first_grid_day(
|
match target.selector_upwards::<Element>(".day") {
|
||||||
state_clone.get_displayed_date(),
|
Some(element) if options.can_select_date => {
|
||||||
options.first_day_of_the_week,
|
let first_day = first_grid_day(
|
||||||
);
|
state_clone.get_displayed_date(),
|
||||||
let day_grid_id = target.parent_element().unwrap().id();
|
options.first_day_of_the_week,
|
||||||
let day_offset = day_grid_id[9..10].parse::<u64>().unwrap() * 7
|
);
|
||||||
+ day_grid_id[10..11].parse::<u64>().unwrap();
|
let day_grid_id = element.id();
|
||||||
state_clone.set_selected_date(first_day + Days::new(day_offset));
|
let day_offset = day_grid_id[9..10].parse::<u64>().unwrap() * 7
|
||||||
display_month(
|
+ day_grid_id[10..11].parse::<u64>().unwrap();
|
||||||
&calendar_clone,
|
state_clone.set_selected_date(first_day + Days::new(day_offset));
|
||||||
state_clone.clone(),
|
display_month(
|
||||||
options,
|
&calendar_clone,
|
||||||
recipe_scheduler,
|
state_clone.clone(),
|
||||||
);
|
options,
|
||||||
} else if target.class_name().contains("remove-scheduled-recipe") {
|
recipe_scheduler,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.class_name().contains("remove-scheduled-recipe") {
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
// Element id format example: "scheduled-recipe-1-2025-05-15".
|
// Element id format example: "scheduled-recipe-1-2025-05-15".
|
||||||
let element_id = target.parent_element().unwrap().id();
|
let element_id = target.parent_element().unwrap().id();
|
||||||
|
|
@ -239,8 +245,6 @@ pub fn setup(
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
const NB_CALENDAR_ROW: u64 = 5;
|
|
||||||
|
|
||||||
fn display_month(
|
fn display_month(
|
||||||
calendar: &Element,
|
calendar: &Element,
|
||||||
state: CalendarState,
|
state: CalendarState,
|
||||||
|
|
@ -268,34 +272,48 @@ fn display_month(
|
||||||
let first_day = first_grid_day(date, options.first_day_of_the_week);
|
let first_day = first_grid_day(date, options.first_day_of_the_week);
|
||||||
let mut current = first_day;
|
let mut current = first_day;
|
||||||
|
|
||||||
for i in 0..NB_CALENDAR_ROW {
|
let nb_of_weeks = {
|
||||||
|
let nb_days_previous_month = if date.month0() == first_day.month0() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
(date.with_day(1).unwrap() - first_day).num_days()
|
||||||
|
};
|
||||||
|
if date.num_days_in_month() + nb_days_previous_month as u8 > 5 * 7 {
|
||||||
|
6
|
||||||
|
} else {
|
||||||
|
5
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
gloo::console::log!(nb_of_weeks);
|
||||||
|
|
||||||
|
for i in 0..6 {
|
||||||
for j in 0..7 {
|
for j in 0..7 {
|
||||||
let day_element: Element = by_id(&format!("day-grid-{}{}", i, j));
|
let day_element: Element = by_id(&format!("day-grid-{}{}", i, j));
|
||||||
|
|
||||||
let day_content: Element = day_element.selector(".number");
|
let day_content: Element = day_element.selector(".number");
|
||||||
day_content.set_inner_html(¤t.day().to_string());
|
|
||||||
|
|
||||||
let mut class_name = String::new();
|
if i < nb_of_weeks {
|
||||||
|
day_content.set_inner_html(¤t.day().to_string());
|
||||||
|
|
||||||
if current.month() == date.month() {
|
let mut classes = vec!["day".to_string()];
|
||||||
if !class_name.is_empty() {
|
|
||||||
class_name += " ";
|
if current.month() == date.month() {
|
||||||
|
classes.push("current-month".to_string());
|
||||||
}
|
}
|
||||||
class_name += "current-month";
|
if current == Local::now().date_naive() {
|
||||||
}
|
classes.push("today".to_string());
|
||||||
if current == Local::now().date_naive() {
|
|
||||||
if !class_name.is_empty() {
|
|
||||||
class_name += " ";
|
|
||||||
}
|
}
|
||||||
class_name += "today";
|
|
||||||
}
|
if options.can_select_date && current == state.get_selected_date() {
|
||||||
if options.can_select_date && current == state.get_selected_date() {
|
classes.push("selected-day".to_string());
|
||||||
if !class_name.is_empty() {
|
|
||||||
class_name += " ";
|
|
||||||
}
|
}
|
||||||
class_name += "selected-day"
|
|
||||||
|
day_element.set_class_name(&classes.join(" "));
|
||||||
|
} else {
|
||||||
|
gloo::console::log!("ok");
|
||||||
|
day_element.set_class_name("");
|
||||||
|
day_content.set_inner_html("");
|
||||||
}
|
}
|
||||||
day_element.set_class_name(&class_name);
|
|
||||||
|
|
||||||
current = current + Days::new(1);
|
current = current + Days::new(1);
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +322,7 @@ fn display_month(
|
||||||
// Load and display scheduled recipes.
|
// Load and display scheduled recipes.
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
let scheduled_recipes = recipe_scheduler
|
let scheduled_recipes = recipe_scheduler
|
||||||
.get_scheduled_recipes(first_day, first_day + Days::new(NB_CALENDAR_ROW * 7))
|
.get_scheduled_recipes(first_day, first_day + Days::new(nb_of_weeks * 7))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@ pub trait SelectorExt {
|
||||||
where
|
where
|
||||||
T: JsCast;
|
T: JsCast;
|
||||||
|
|
||||||
|
fn selector_upwards<T>(&self, selector: &str) -> Option<T>
|
||||||
|
where
|
||||||
|
T: JsCast;
|
||||||
|
|
||||||
fn deep_clone(&self) -> Self;
|
fn deep_clone(&self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,6 +45,25 @@ impl SelectorExt for Element {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn selector_upwards<T>(&self, selector: &str) -> Option<T>
|
||||||
|
where
|
||||||
|
T: JsCast,
|
||||||
|
{
|
||||||
|
let mut current = self.clone();
|
||||||
|
// while let Some(parent) = current.parent_element() {
|
||||||
|
loop {
|
||||||
|
if let Ok(true) = current.matches(selector) {
|
||||||
|
return Some(current.dyn_into::<T>().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(parent) = current.parent_element() {
|
||||||
|
current = parent;
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deep_clone(&self) -> Self {
|
fn deep_clone(&self) -> Self {
|
||||||
self.clone_node_with_deep(true)
|
self.clone_node_with_deep(true)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue